From b00eef42deee6b545a7830fbad6014c286ae0449 Mon Sep 17 00:00:00 2001 From: Martin Panzer Date: Wed, 10 Feb 2021 21:25:55 +0100 Subject: [PATCH 0001/2077] Improve transactional observer without jta warning The warning now includes, that the observers are still triggered, which is a clearer messaging. --- .../src/main/java/io/quarkus/arc/processor/ObserverInfo.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ObserverInfo.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ObserverInfo.java index 298109e92dbf1..2cf643e949e04 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ObserverInfo.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ObserverInfo.java @@ -99,8 +99,9 @@ static ObserverInfo create(String id, BeanDeployment beanDeployment, DotName bea } else { info = beanClass.toString(); } - LOGGER.warnf("The observer %s makes use of %s transactional observers but no " + - "JTA capabilities were detected.", info, transactionPhase); + LOGGER.warnf( + "The observer %s makes use of %s transactional observers but no JTA capabilities were detected. Transactional observers will be notified at the same time as other observers.", + info, transactionPhase); } return new ObserverInfo(id, beanDeployment, beanClass, declaringBean, observerMethod, injection, eventParameter, isAsync, priority, reception, transactionPhase, observedType, qualifiers, notify); From 46dd766dbc1dd5fb843272162608b30f38a17b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 3 May 2021 14:59:30 +0200 Subject: [PATCH 0002/2077] Sync FastBootMetadataBuilder#applyMetadataBuilderContributor with EntityManagerFactoryBuilderImpl#applyMetadataBuilderContributor from ORM 5.5 This code was updated since it was copied years ago. --- .../runtime/boot/FastBootMetadataBuilder.java | 58 ++++++++++++------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/boot/FastBootMetadataBuilder.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/boot/FastBootMetadataBuilder.java index 05353c01bffe4..2b4fc02206aa6 100644 --- a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/boot/FastBootMetadataBuilder.java +++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/boot/FastBootMetadataBuilder.java @@ -574,9 +574,7 @@ protected void populate(MetadataBuilder metamodelBuilder, List metadataBuilderContributorImplClass = null; + MetadataBuilderContributor metadataBuilderContributor = loadSettingInstance( + EntityManagerFactoryBuilderImpl.METADATA_BUILDER_CONTRIBUTOR, + metadataBuilderContributorSetting, + MetadataBuilderContributor.class); - if (metadataBuilderContributorSetting instanceof MetadataBuilderContributor) { - metadataBuilderContributor = (MetadataBuilderContributor) metadataBuilderContributorSetting; - } else if (metadataBuilderContributorSetting instanceof Class) { - metadataBuilderContributorImplClass = (Class) metadataBuilderContributorSetting; - } else if (metadataBuilderContributorSetting instanceof String) { - final ClassLoaderService classLoaderService = standardServiceRegistry.getService(ClassLoaderService.class); + if (metadataBuilderContributor != null) { + metadataBuilderContributor.contribute(metamodelBuilder); + } + } - metadataBuilderContributorImplClass = classLoaderService - .classForName((String) metadataBuilderContributorSetting); + @SuppressWarnings("unchecked") + private T loadSettingInstance(String settingName, Object settingValue, Class clazz) { + T instance = null; + Class instanceClass = null; + + if (clazz.isAssignableFrom(settingValue.getClass())) { + instance = (T) settingValue; + } else if (settingValue instanceof Class) { + instanceClass = (Class) settingValue; + } else if (settingValue instanceof String) { + String settingStringValue = (String) settingValue; + if (standardServiceRegistry != null) { + final ClassLoaderService classLoaderService = standardServiceRegistry.getService(ClassLoaderService.class); + + instanceClass = classLoaderService.classForName(settingStringValue); + } else { + try { + instanceClass = (Class) Class.forName(settingStringValue); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("Can't load class: " + settingStringValue, e); + } + } } else { throw new IllegalArgumentException( - "The provided " + EntityManagerFactoryBuilderImpl.METADATA_BUILDER_CONTRIBUTOR + " setting value [" - + metadataBuilderContributorSetting + "] is not supported!"); + "The provided " + settingName + " setting value [" + settingValue + "] is not supported!"); } - if (metadataBuilderContributorImplClass != null) { + if (instanceClass != null) { try { - metadataBuilderContributor = metadataBuilderContributorImplClass.getDeclaredConstructor().newInstance(); + instance = instanceClass.getConstructor().newInstance(); } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { - throw new IllegalArgumentException("The MetadataBuilderContributor class [" - + metadataBuilderContributorImplClass + "] could not be instantiated!", e); + throw new IllegalArgumentException( + "The " + clazz.getSimpleName() + " class [" + instanceClass + "] could not be instantiated!", + e); } } - if (metadataBuilderContributor != null) { - metadataBuilderContributor.contribute(metamodelBuilder); - } + return instance; } } From aefa828a4e56e940140ab4c4e30e0fea2b79ab04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 3 May 2021 15:27:22 +0200 Subject: [PATCH 0003/2077] Add property quarkus.hibernate-orm.metadata-builder-contributor --- .../HibernateOrmConfigPersistenceUnit.java | 17 +++++++++++++++++ .../orm/deployment/HibernateOrmProcessor.java | 6 ++++++ 2 files changed, 23 insertions(+) diff --git a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmConfigPersistenceUnit.java b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmConfigPersistenceUnit.java index 891c406ff01b7..a935996be4225 100644 --- a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmConfigPersistenceUnit.java +++ b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmConfigPersistenceUnit.java @@ -112,6 +112,22 @@ public class HibernateOrmConfigPersistenceUnit { @ConfigItem public Optional implicitNamingStrategy; + /** + * Class name of a custom {@link org.hibernate.boot.spi.MetadataBuilderContributor} implementation. + * + * [NOTE] + * ==== + * Not all customization options exposed by {@link org.hibernate.boot.MetadataBuilder} + * will work correctly. Stay clear of options related to classpath scanning in particular. + * + * This setting is exposed mainly to allow registration of types, converters and SQL functions. + * ==== + * + * @asciidoclet + */ + @ConfigItem + public Optional metadataBuilderContributor; + /** * Query related configuration. */ @@ -183,6 +199,7 @@ public boolean isAnyPropertySet() { maxFetchDepth.isPresent() || physicalNamingStrategy.isPresent() || implicitNamingStrategy.isPresent() || + metadataBuilderContributor.isPresent() || query.isAnyPropertySet() || database.isAnyPropertySet() || jdbc.isAnyPropertySet() || diff --git a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java index 33f6140317723..c7c7411cbbebe 100644 --- a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java +++ b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java @@ -43,6 +43,7 @@ import org.hibernate.cfg.beanvalidation.BeanValidationIntegrator; import org.hibernate.integrator.spi.Integrator; import org.hibernate.internal.util.collections.ArrayHelper; +import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl; import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor; import org.hibernate.loader.BatchFetchStyle; import org.jboss.jandex.AnnotationInstance; @@ -791,6 +792,11 @@ private static void producePersistenceUnitDescriptorFromConfig( namingStrategy -> descriptor.getProperties() .setProperty(AvailableSettings.IMPLICIT_NAMING_STRATEGY, namingStrategy)); + // Metadata builder contributor + persistenceUnitConfig.metadataBuilderContributor.ifPresent( + className -> descriptor.getProperties() + .setProperty(EntityManagerFactoryBuilderImpl.METADATA_BUILDER_CONTRIBUTOR, className)); + //charset descriptor.getProperties().setProperty(AvailableSettings.HBM2DDL_CHARSET_NAME, persistenceUnitConfig.database.charset.name()); From 5bf738044c459c3979315b5301e506e68099861a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 3 May 2021 16:32:29 +0200 Subject: [PATCH 0004/2077] Fix PrevalidatedQuarkusMetadata ignoring custom SQL functions --- .../recording/PrevalidatedQuarkusMetadata.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/recording/PrevalidatedQuarkusMetadata.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/recording/PrevalidatedQuarkusMetadata.java index 4cbb4d052b168..f63e9ff8ebb02 100644 --- a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/recording/PrevalidatedQuarkusMetadata.java +++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/recording/PrevalidatedQuarkusMetadata.java @@ -64,9 +64,18 @@ public static PrevalidatedQuarkusMetadata validateAndWrap(final MetadataImpl ori // New helpers on this Quarkus specific metadata; these are useful to boot and manage the recorded state: public SessionFactoryOptionsBuilder buildSessionFactoryOptionsBuilder() { - return new SessionFactoryOptionsBuilder( + SessionFactoryOptionsBuilder builder = new SessionFactoryOptionsBuilder( metadata.getMetadataBuildingOptions().getServiceRegistry(), metadata.getBootstrapContext()); + // This would normally be done by the constructor of SessionFactoryBuilderImpl, + // but we don't use a builder to create the session factory, for some reason. + Map sqlFunctions = metadata.getSqlFunctionMap(); + if (sqlFunctions != null) { + for (Map.Entry entry : sqlFunctions.entrySet()) { + builder.applySqlFunction(entry.getKey(), entry.getValue()); + } + } + return builder; } //Relevant overrides: From f9e3fb3df17959da38e5a98ef42ca7787e95b5ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 3 May 2021 16:04:18 +0200 Subject: [PATCH 0005/2077] Test custom metadata builder contributors --- .../CustomMetadataBuilderContributor.java | 49 +++++++++++++++++++ .../MetadataBuilderContributorTest.java | 40 +++++++++++++++ .../metadatabuildercontributor/MyEntity.java | 31 ++++++++++++ ...on-metadata-builder-contributor.properties | 7 +++ 4 files changed, 127 insertions(+) create mode 100644 extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/metadatabuildercontributor/CustomMetadataBuilderContributor.java create mode 100644 extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/metadatabuildercontributor/MetadataBuilderContributorTest.java create mode 100644 extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/metadatabuildercontributor/MyEntity.java create mode 100644 extensions/hibernate-orm/deployment/src/test/resources/application-metadata-builder-contributor.properties diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/metadatabuildercontributor/CustomMetadataBuilderContributor.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/metadatabuildercontributor/CustomMetadataBuilderContributor.java new file mode 100644 index 0000000000000..5f05078a75743 --- /dev/null +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/metadatabuildercontributor/CustomMetadataBuilderContributor.java @@ -0,0 +1,49 @@ +package io.quarkus.hibernate.orm.metadatabuildercontributor; + +import java.util.List; + +import org.hibernate.QueryException; +import org.hibernate.boot.MetadataBuilder; +import org.hibernate.boot.spi.MetadataBuilderContributor; +import org.hibernate.dialect.function.SQLFunction; +import org.hibernate.engine.spi.Mapping; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.type.StringType; +import org.hibernate.type.Type; + +public class CustomMetadataBuilderContributor implements MetadataBuilderContributor { + @Override + public void contribute(MetadataBuilder metadataBuilder) { + metadataBuilder.applySqlFunction( + "addHardcodedSuffix", + new HardcodedSuffixFunction("_some_suffix")); + } + + private static final class HardcodedSuffixFunction implements SQLFunction { + private final String suffix; + + private HardcodedSuffixFunction(String suffix) { + this.suffix = suffix; + } + + @Override + public boolean hasArguments() { + return true; + } + + @Override + public boolean hasParenthesesIfNoArguments() { + return false; + } + + @Override + public Type getReturnType(Type firstArgumentType, Mapping mapping) throws QueryException { + return StringType.INSTANCE; + } + + @Override + public String render(Type firstArgumentType, List arguments, SessionFactoryImplementor factory) throws QueryException { + return "(" + arguments.get(0) + " || '" + suffix + "')"; + } + } +} diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/metadatabuildercontributor/MetadataBuilderContributorTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/metadatabuildercontributor/MetadataBuilderContributorTest.java new file mode 100644 index 0000000000000..c01ac72edd1fe --- /dev/null +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/metadatabuildercontributor/MetadataBuilderContributorTest.java @@ -0,0 +1,40 @@ +package io.quarkus.hibernate.orm.metadatabuildercontributor; + +import static org.assertj.core.api.Assertions.assertThat; + +import javax.inject.Inject; +import javax.persistence.EntityManager; +import javax.transaction.Transactional; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class MetadataBuilderContributorTest { + + @RegisterExtension + static QuarkusUnitTest runner = new QuarkusUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addClass(MyEntity.class) + .addClass(CustomMetadataBuilderContributor.class) + .addAsResource("application-metadata-builder-contributor.properties", "application.properties")); + + @Inject + EntityManager entityManager; + + @Test + @Transactional + public void test() { + MyEntity entity = new MyEntity(); + entity.setName("some_name"); + entityManager.persist(entity); + + assertThat(entityManager.createQuery("select addHardcodedSuffix(e.name) from MyEntity e", String.class) + .getSingleResult()) + .isEqualTo("some_name_some_suffix"); + } + +} diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/metadatabuildercontributor/MyEntity.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/metadatabuildercontributor/MyEntity.java new file mode 100644 index 0000000000000..f359e6333e1e0 --- /dev/null +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/metadatabuildercontributor/MyEntity.java @@ -0,0 +1,31 @@ +package io.quarkus.hibernate.orm.metadatabuildercontributor; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class MyEntity { + @Id + private long id; + + private String name; + + public MyEntity() { + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/extensions/hibernate-orm/deployment/src/test/resources/application-metadata-builder-contributor.properties b/extensions/hibernate-orm/deployment/src/test/resources/application-metadata-builder-contributor.properties new file mode 100644 index 0000000000000..df24d17b483c2 --- /dev/null +++ b/extensions/hibernate-orm/deployment/src/test/resources/application-metadata-builder-contributor.properties @@ -0,0 +1,7 @@ +quarkus.datasource.db-kind=h2 +quarkus.datasource.jdbc.url=jdbc:h2:mem:test + +quarkus.hibernate-orm.dialect=org.hibernate.dialect.H2Dialect +quarkus.hibernate-orm.log.sql=true +quarkus.hibernate-orm.database.generation=drop-and-create +quarkus.hibernate-orm.metadata-builder-contributor=io.quarkus.hibernate.orm.metadatabuildercontributor.CustomMetadataBuilderContributor \ No newline at end of file From 7eedb27412ad03093ca401586c3cd245ce8f389b Mon Sep 17 00:00:00 2001 From: Falko Modler Date: Mon, 10 May 2021 15:44:31 +0200 Subject: [PATCH 0006/2077] CI: Fix build of TCKS modules not using GIB/incremental args --- .github/workflows/ci-actions-incremental.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-actions-incremental.yml b/.github/workflows/ci-actions-incremental.yml index 16add2199c168..263b3f2523a01 100644 --- a/.github/workflows/ci-actions-incremental.yml +++ b/.github/workflows/ci-actions-incremental.yml @@ -617,7 +617,7 @@ jobs: tcks-test: name: MicroProfile TCKs Tests - needs: calculate-test-jobs + needs: [build-jdk11, calculate-test-jobs] # Skip main in forks if: "needs.calculate-test-jobs.outputs.run_tcks == 'true' && (github.repository == 'quarkusio/quarkus' || !endsWith(github.ref, '/main'))" runs-on: ubuntu-latest From 3382fba591dd71d812d4624e7e0292a0d08c9e9b Mon Sep 17 00:00:00 2001 From: Falko Modler Date: Mon, 10 May 2021 15:44:31 +0200 Subject: [PATCH 0007/2077] CI: Use mvnw from resteasy-reative-testsuite --- tcks/resteasy-reactive/pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tcks/resteasy-reactive/pom.xml b/tcks/resteasy-reactive/pom.xml index c2097363a6220..522115118b8de 100644 --- a/tcks/resteasy-reactive/pom.xml +++ b/tcks/resteasy-reactive/pom.xml @@ -16,7 +16,7 @@ - 82698545ef2f09b6b826d650502238cebf9f6171 + e3cd2c5e5b9262ae5d1197005c542fdd02f9d4ff ${skipTests} ${exec.skip} @@ -71,8 +71,8 @@ exec - mvn - -e -B --settings ${session.request.userSettingsFile.path} clean install ${resteasy-reactive-testsuite.mvn.args} -Dsurefire.excludedEnvironmentVariables=MAVEN_OPTS + mvnw + -e -B --settings ${session.request.userSettingsFile.path} clean install ${resteasy-reactive-testsuite.mvn.args} ${resteasy-reactive-testsuite.test.skip} From f31090298f7fa6b8f9cff8495863354b976d2983 Mon Sep 17 00:00:00 2001 From: Guillaume Le Floch Date: Mon, 10 May 2021 17:38:14 +0200 Subject: [PATCH 0008/2077] Update kotlin version in gradle sample project --- .../test/resources/bean-in-testsources-project/build.gradle | 4 ++-- .../src/test/resources/kotlin-grpc-project/build.gradle | 4 ++-- .../resources/multi-module-kotlin-project/gradle.properties | 2 +- .../src/test/resources/multi-source-project/build.gradle | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/integration-tests/gradle/src/test/resources/bean-in-testsources-project/build.gradle b/integration-tests/gradle/src/test/resources/bean-in-testsources-project/build.gradle index 970cb4931194d..4dc476b537728 100644 --- a/integration-tests/gradle/src/test/resources/bean-in-testsources-project/build.gradle +++ b/integration-tests/gradle/src/test/resources/bean-in-testsources-project/build.gradle @@ -1,8 +1,8 @@ plugins { id 'java' id 'io.quarkus' - id 'org.jetbrains.kotlin.jvm' version "1.3.72" - id "org.jetbrains.kotlin.plugin.allopen" version "1.3.72" + id 'org.jetbrains.kotlin.jvm' version "1.4.32" + id "org.jetbrains.kotlin.plugin.allopen" version "1.4.32" } repositories { diff --git a/integration-tests/gradle/src/test/resources/kotlin-grpc-project/build.gradle b/integration-tests/gradle/src/test/resources/kotlin-grpc-project/build.gradle index 31a6214b5986d..2ea1d518e2c32 100644 --- a/integration-tests/gradle/src/test/resources/kotlin-grpc-project/build.gradle +++ b/integration-tests/gradle/src/test/resources/kotlin-grpc-project/build.gradle @@ -1,6 +1,6 @@ plugins { - id 'org.jetbrains.kotlin.jvm' version "1.3.72" - id "org.jetbrains.kotlin.plugin.allopen" version "1.3.72" + id 'org.jetbrains.kotlin.jvm' version "1.4.32" + id "org.jetbrains.kotlin.plugin.allopen" version "1.4.32" id 'io.quarkus' } diff --git a/integration-tests/gradle/src/test/resources/multi-module-kotlin-project/gradle.properties b/integration-tests/gradle/src/test/resources/multi-module-kotlin-project/gradle.properties index bf4f8e498f423..84258023fa3ec 100644 --- a/integration-tests/gradle/src/test/resources/multi-module-kotlin-project/gradle.properties +++ b/integration-tests/gradle/src/test/resources/multi-module-kotlin-project/gradle.properties @@ -3,5 +3,5 @@ quarkusPlatformArtifactId=quarkus-bom quarkusPlatformGroupId=io.quarkus -kotlinVersion=1.3.72 +kotlinVersion=1.4.32 diff --git a/integration-tests/gradle/src/test/resources/multi-source-project/build.gradle b/integration-tests/gradle/src/test/resources/multi-source-project/build.gradle index 3f8df9a1a3e65..9613862160c6e 100644 --- a/integration-tests/gradle/src/test/resources/multi-source-project/build.gradle +++ b/integration-tests/gradle/src/test/resources/multi-source-project/build.gradle @@ -1,7 +1,7 @@ plugins { id 'java' - id 'org.jetbrains.kotlin.jvm' version "1.3.72" - id "org.jetbrains.kotlin.plugin.allopen" version "1.3.72" + id 'org.jetbrains.kotlin.jvm' version "1.4.32" + id "org.jetbrains.kotlin.plugin.allopen" version "1.4.32" id 'io.quarkus' } From d45b1d430c6726ee1b6027bf6417399b5477ec0f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 May 2021 19:01:39 +0000 Subject: [PATCH 0009/2077] Bump awaitility from 4.0.3 to 4.1.0 in /devtools/gradle Bumps [awaitility](https://github.com/awaitility/awaitility) from 4.0.3 to 4.1.0. - [Release notes](https://github.com/awaitility/awaitility/releases) - [Changelog](https://github.com/awaitility/awaitility/blob/master/changelog.txt) - [Commits](https://github.com/awaitility/awaitility/commits/awaitility-4.1.0) Signed-off-by: dependabot[bot] --- devtools/gradle/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devtools/gradle/build.gradle b/devtools/gradle/build.gradle index 294c123174295..289c8baaf65b2 100644 --- a/devtools/gradle/build.gradle +++ b/devtools/gradle/build.gradle @@ -38,7 +38,7 @@ dependencies { testImplementation 'org.mockito:mockito-core:3.9.0' testImplementation 'org.assertj:assertj-core:3.19.0' testImplementation 'org.junit.jupiter:junit-jupiter:5.7.1' - testImplementation 'org.awaitility:awaitility:4.0.3' + testImplementation 'org.awaitility:awaitility:4.1.0' testImplementation "io.quarkus:quarkus-devmode-test-utils:${version}" testImplementation gradleTestKit() } From 85469af5fe79adfa0aa397f3608341d743a9e0d2 Mon Sep 17 00:00:00 2001 From: adrianfiedler Date: Sun, 9 May 2021 20:33:40 +0200 Subject: [PATCH 0010/2077] Update scheduler-reference.adoc fix #16942: Add example of pause/resume of specific identity --- docs/src/main/asciidoc/scheduler-reference.adoc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/src/main/asciidoc/scheduler-reference.adoc b/docs/src/main/asciidoc/scheduler-reference.adoc index b64ba1308585c..5c5310889fd17 100644 --- a/docs/src/main/asciidoc/scheduler-reference.adoc +++ b/docs/src/main/asciidoc/scheduler-reference.adoc @@ -201,7 +201,7 @@ void nonConcurrent() { == Scheduler -Quarkus provides a built-in bean of type `io.quarkus.scheduler.Scheduler` that can be injected and used to pause/resume the scheduler. +Quarkus provides a built-in bean of type `io.quarkus.scheduler.Scheduler` that can be injected and used to pause/resume the scheduler and individual scheduled methods identified by a specific `Scheduled#identity()`. .Scheduler Injection Example [source,java] @@ -215,15 +215,19 @@ class MyService { void ping() { scheduler.pause(); <1> + scheduler.pause("myIdentity"); <2> if (scheduler.isRunning()) { throw new IllegalStateException("This should never happen!"); } - scheduler.resume(); <2> + scheduler.resume("myIdentity"); <3> + scheduler.resume(); <4> } } ---- <1> Pause all triggers. -<2> Resume the scheduler. +<2> Pause a specific scheduled method by its identity +<3> Resume a specific scheduled method by its identity +<4> Resume the scheduler. == Programmatic Scheduling From 8e1cbdcf81f4ac55ab189b40891e10e711ec0106 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 May 2021 20:20:41 +0000 Subject: [PATCH 0011/2077] Bump awaitility from 4.0.3 to 4.1.0 in /integration-tests/gradle Bumps [awaitility](https://github.com/awaitility/awaitility) from 4.0.3 to 4.1.0. - [Release notes](https://github.com/awaitility/awaitility/releases) - [Changelog](https://github.com/awaitility/awaitility/blob/master/changelog.txt) - [Commits](https://github.com/awaitility/awaitility/commits/awaitility-4.1.0) Signed-off-by: dependabot[bot] --- integration-tests/gradle/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/gradle/build.gradle b/integration-tests/gradle/build.gradle index ae76a80081196..a3bff499f8d40 100644 --- a/integration-tests/gradle/build.gradle +++ b/integration-tests/gradle/build.gradle @@ -38,7 +38,7 @@ dependencies { testImplementation 'org.mockito:mockito-core:3.9.0' testImplementation 'org.assertj:assertj-core:3.19.0' testImplementation 'org.junit.jupiter:junit-jupiter:5.7.1' - testImplementation 'org.awaitility:awaitility:4.0.3' + testImplementation 'org.awaitility:awaitility:4.1.0' } processTestResources { From b3d3788ae92542d5fb39d89488890e16d64cec90 Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Fri, 7 May 2021 12:42:21 -0300 Subject: [PATCH 0012/2077] Introduce UberJarMergedResourceBuildItem and UberJarIgnoredResourceBuildItem Fixes #5677 --- .../UberJarIgnoredResourceBuildItem.java | 20 +++++ .../UberJarMergedResourceBuildItem.java | 20 +++++ .../pkg/steps/JarResultBuildStep.java | 60 ++++++++++++-- .../deployment/UberJarConfigBuildStep.java | 22 ++++++ .../UberJarIgnoredResourceBuildItemTest.java | 52 +++++++++++++ .../UberJarMergedResourceBuildItemTest.java | 78 +++++++++++++++++++ 6 files changed, 244 insertions(+), 8 deletions(-) create mode 100644 core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/UberJarIgnoredResourceBuildItem.java create mode 100644 core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/UberJarMergedResourceBuildItem.java create mode 100644 core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/UberJarConfigBuildStep.java create mode 100644 core/test-extension/deployment/src/test/java/io/quarkus/deployment/pkg/builditem/UberJarIgnoredResourceBuildItemTest.java create mode 100644 core/test-extension/deployment/src/test/java/io/quarkus/deployment/pkg/builditem/UberJarMergedResourceBuildItemTest.java diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/UberJarIgnoredResourceBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/UberJarIgnoredResourceBuildItem.java new file mode 100644 index 0000000000000..00551260490b1 --- /dev/null +++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/UberJarIgnoredResourceBuildItem.java @@ -0,0 +1,20 @@ +package io.quarkus.deployment.pkg.builditem; + +import io.quarkus.builder.item.MultiBuildItem; +import io.smallrye.common.constraint.Assert; + +/** + * Ignore resources when building an Uber Jar + */ +public final class UberJarIgnoredResourceBuildItem extends MultiBuildItem { + + private final String path; + + public UberJarIgnoredResourceBuildItem(String path) { + this.path = Assert.checkNotEmptyParam("UberJarIgnoredResourceBuildItem.path", path); + } + + public String getPath() { + return path; + } +} diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/UberJarMergedResourceBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/UberJarMergedResourceBuildItem.java new file mode 100644 index 0000000000000..d38546c55316d --- /dev/null +++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/UberJarMergedResourceBuildItem.java @@ -0,0 +1,20 @@ +package io.quarkus.deployment.pkg.builditem; + +import io.quarkus.builder.item.MultiBuildItem; +import io.smallrye.common.constraint.Assert; + +/** + * Merge duplicate resources from multiple JARs when building an Uber Jar + */ +public final class UberJarMergedResourceBuildItem extends MultiBuildItem { + + private final String path; + + public UberJarMergedResourceBuildItem(String path) { + this.path = Assert.checkNotEmptyParam("UberJarMergedResourceBuildItem.path", path); + } + + public String getPath() { + return path; + } +} diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/JarResultBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/JarResultBuildStep.java index cba8cad2f3ce7..92d924d1a5154 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/JarResultBuildStep.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/JarResultBuildStep.java @@ -77,6 +77,8 @@ import io.quarkus.deployment.pkg.builditem.LegacyJarRequiredBuildItem; import io.quarkus.deployment.pkg.builditem.NativeImageSourceJarBuildItem; import io.quarkus.deployment.pkg.builditem.OutputTargetBuildItem; +import io.quarkus.deployment.pkg.builditem.UberJarIgnoredResourceBuildItem; +import io.quarkus.deployment.pkg.builditem.UberJarMergedResourceBuildItem; import io.quarkus.deployment.pkg.builditem.UberJarRequiredBuildItem; import io.quarkus.deployment.util.FileUtil; @@ -135,21 +137,37 @@ public boolean test(String path) { }; private static final Logger log = Logger.getLogger(JarResultBuildStep.class); + private static final BiPredicate IS_JSON_FILE_PREDICATE = new IsJsonFilePredicate(); + public static final String DEPLOYMENT_CLASS_PATH_DAT = "deployment-class-path.dat"; + public static final String BUILD_SYSTEM_PROPERTIES = "build-system.properties"; + public static final String DEPLOYMENT_LIB = "deployment"; + public static final String APPMODEL_DAT = "appmodel.dat"; + public static final String QUARKUS_RUN_JAR = "quarkus-run.jar"; + public static final String QUARKUS_APP_DEPS = "quarkus-app-dependencies.txt"; + public static final String BOOT_LIB = "boot"; + public static final String LIB = "lib"; + public static final String MAIN = "main"; + public static final String GENERATED_BYTECODE_JAR = "generated-bytecode.jar"; + public static final String TRANSFORMED_BYTECODE_JAR = "transformed-bytecode.jar"; + public static final String APP = "app"; + public static final String QUARKUS = "quarkus"; + public static final String DEFAULT_FAST_JAR_DIRECTORY_NAME = "quarkus-app"; + public static final String MP_CONFIG_FILE = "META-INF/microprofile-config.properties"; @BuildStep @@ -188,6 +206,8 @@ public JarBuildItem buildRunnerJar(CurateOutcomeBuildItem curateOutcomeBuildItem List generatedClasses, List generatedResources, List uberJarRequired, + List uberJarMergedResourceBuildItems, + List uberJarIgnoredResourceBuildItems, List legacyJarRequired, QuarkusBuildCloseablesBuildItem closeablesBuildItem, List additionalApplicationArchiveBuildItems, @@ -205,7 +225,8 @@ public JarBuildItem buildRunnerJar(CurateOutcomeBuildItem curateOutcomeBuildItem if (legacyJarRequired.isEmpty() && (!uberJarRequired.isEmpty() || packageConfig.type.equalsIgnoreCase(PackageConfig.UBER_JAR))) { return buildUberJar(curateOutcomeBuildItem, outputTargetBuildItem, transformedClasses, applicationArchivesBuildItem, - packageConfig, applicationInfo, generatedClasses, generatedResources, mainClassBuildItem); + packageConfig, applicationInfo, generatedClasses, generatedResources, uberJarMergedResourceBuildItems, + uberJarIgnoredResourceBuildItems, mainClassBuildItem); } else if (!legacyJarRequired.isEmpty() || packageConfig.isLegacyJar() || packageConfig.type.equalsIgnoreCase(PackageConfig.LEGACY)) { return buildLegacyThinJar(curateOutcomeBuildItem, outputTargetBuildItem, transformedClasses, @@ -252,6 +273,8 @@ private JarBuildItem buildUberJar(CurateOutcomeBuildItem curateOutcomeBuildItem, ApplicationInfoBuildItem applicationInfo, List generatedClasses, List generatedResources, + List mergeResources, + List ignoredResources, MainClassBuildItem mainClassBuildItem) throws Exception { //we use the -runner jar name, unless we are building both types @@ -267,6 +290,8 @@ private JarBuildItem buildUberJar(CurateOutcomeBuildItem curateOutcomeBuildItem, applicationInfo, generatedClasses, generatedResources, + mergeResources, + ignoredResources, mainClassBuildItem, runnerJar); @@ -292,6 +317,8 @@ private void buildUberJar0(CurateOutcomeBuildItem curateOutcomeBuildItem, ApplicationInfoBuildItem applicationInfo, List generatedClasses, List generatedResources, + List mergedResources, + List ignoredResources, MainClassBuildItem mainClassBuildItem, Path runnerJar) throws Exception { try (FileSystem runnerZipFs = ZipUtils.newZip(runnerJar)) { @@ -301,8 +328,14 @@ private void buildUberJar0(CurateOutcomeBuildItem curateOutcomeBuildItem, final Map seen = new HashMap<>(); final Map> duplicateCatcher = new HashMap<>(); final Map> concatenatedEntries = new HashMap<>(); + final Set mergeResourcePaths = mergedResources.stream() + .map(UberJarMergedResourceBuildItem::getPath) + .collect(Collectors.toSet()); Set finalIgnoredEntries = new HashSet<>(IGNORED_ENTRIES); packageConfig.userConfiguredIgnoredEntries.ifPresent(finalIgnoredEntries::addAll); + ignoredResources.stream() + .map(UberJarIgnoredResourceBuildItem::getPath) + .forEach(finalIgnoredEntries::add); final List appDeps = curateOutcomeBuildItem.getEffectiveModel().getUserDependencies(); @@ -328,12 +361,13 @@ private void buildUberJar0(CurateOutcomeBuildItem curateOutcomeBuildItem, try (FileSystem artifactFs = ZipUtils.newFileSystem(resolvedDep)) { for (final Path root : artifactFs.getRootDirectories()) { walkFileDependencyForDependency(root, runnerZipFs, seen, duplicateCatcher, concatenatedEntries, - finalIgnoredEntries, appDep, transformedFromThisArchive); + finalIgnoredEntries, appDep, transformedFromThisArchive, mergeResourcePaths); } } } else { walkFileDependencyForDependency(resolvedDep, runnerZipFs, seen, duplicateCatcher, - concatenatedEntries, finalIgnoredEntries, appDep, transformedFromThisArchive); + concatenatedEntries, finalIgnoredEntries, appDep, transformedFromThisArchive, + mergeResourcePaths); } } } @@ -382,7 +416,8 @@ private static boolean includeAppDep(AppDependency appDep, Optional seen, Map> duplicateCatcher, Map> concatenatedEntries, - Set finalIgnoredEntries, AppDependency appDep, Set transformedFromThisArchive) throws IOException { + Set finalIgnoredEntries, AppDependency appDep, Set transformedFromThisArchive, + Set mergeResourcePaths) throws IOException { final Path metaInfDir = root.resolve("META-INF"); Files.walkFileTree(root, EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, new SimpleFileVisitor() { @@ -414,7 +449,8 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) boolean transformed = transformedFromThisArchive != null && transformedFromThisArchive.contains(relativePath); if (!transformed) { - if (CONCATENATED_ENTRIES_PREDICATE.test(relativePath)) { + if (CONCATENATED_ENTRIES_PREDICATE.test(relativePath) + || mergeResourcePaths.contains(relativePath)) { concatenatedEntries.computeIfAbsent(relativePath, (u) -> new ArrayList<>()) .add(Files.readAllBytes(file)); return FileVisitResult.CONTINUE; @@ -845,7 +881,6 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) /** * Native images are built from a specially created jar file. This allows for changes in how the jar file is generated. - * */ @BuildStep public NativeImageSourceJarBuildItem buildNativeImageJar(CurateOutcomeBuildItem curateOutcomeBuildItem, @@ -858,7 +893,9 @@ public NativeImageSourceJarBuildItem buildNativeImageJar(CurateOutcomeBuildItem List nativeImageResources, List generatedResources, MainClassBuildItem mainClassBuildItem, - List uberJarRequired) throws Exception { + List uberJarRequired, + List mergeResources, + List ignoreResources) throws Exception { Path targetDirectory = outputTargetBuildItem.getOutputDirectory() .resolve(outputTargetBuildItem.getBaseName() + "-native-image-source-jar"); IoUtils.createOrEmptyDir(targetDirectory); @@ -877,7 +914,9 @@ public NativeImageSourceJarBuildItem buildNativeImageJar(CurateOutcomeBuildItem final NativeImageSourceJarBuildItem nativeImageSourceJarBuildItem = buildNativeImageUberJar(curateOutcomeBuildItem, outputTargetBuildItem, transformedClasses, applicationArchivesBuildItem, - packageConfig, applicationInfo, allClasses, generatedResources, mainClassBuildItem, targetDirectory); + packageConfig, applicationInfo, allClasses, generatedResources, mergeResources, + ignoreResources, mainClassBuildItem, + targetDirectory); // additionally copy any json config files to a location accessible by native-image tool during // native-image generation copyJsonConfigFiles(applicationArchivesBuildItem, targetDirectory); @@ -926,6 +965,8 @@ private NativeImageSourceJarBuildItem buildNativeImageUberJar(CurateOutcomeBuild ApplicationInfoBuildItem applicationInfo, List generatedClasses, List generatedResources, + List mergeResources, + List ignoreResources, MainClassBuildItem mainClassBuildItem, Path targetDirectory) throws Exception { //we use the -runner jar name, unless we are building both types @@ -940,6 +981,8 @@ private NativeImageSourceJarBuildItem buildNativeImageUberJar(CurateOutcomeBuild applicationInfo, generatedClasses, generatedResources, + mergeResources, + ignoreResources, mainClassBuildItem, runnerJar); @@ -1126,6 +1169,7 @@ private void copyCommonContent(FileSystem runnerZipFs, Map> for (Map.Entry> entry : concatenatedEntries.entrySet()) { try (final OutputStream os = wrapForJDK8232879( Files.newOutputStream(runnerZipFs.getPath(entry.getKey())))) { + // TODO: Handle merging of XMLs for (byte[] i : entry.getValue()) { os.write(i); os.write('\n'); diff --git a/core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/UberJarConfigBuildStep.java b/core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/UberJarConfigBuildStep.java new file mode 100644 index 0000000000000..5299b7832ebb8 --- /dev/null +++ b/core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/UberJarConfigBuildStep.java @@ -0,0 +1,22 @@ +package io.quarkus.extest.deployment; + +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.pkg.builditem.UberJarIgnoredResourceBuildItem; +import io.quarkus.deployment.pkg.builditem.UberJarMergedResourceBuildItem; + +/** + * Used in UberJarMergedResourceBuildItemTest + */ +public class UberJarConfigBuildStep { + + @BuildStep + UberJarMergedResourceBuildItem uberJarMergedResourceBuildItem() { + return new UberJarMergedResourceBuildItem("META-INF/cxf/bus-extensions.txt"); + } + + @BuildStep + UberJarIgnoredResourceBuildItem uberJarIgnoredResourceBuildItem() { + return new UberJarIgnoredResourceBuildItem("META-INF/cxf/cxf.fixml"); + } + +} diff --git a/core/test-extension/deployment/src/test/java/io/quarkus/deployment/pkg/builditem/UberJarIgnoredResourceBuildItemTest.java b/core/test-extension/deployment/src/test/java/io/quarkus/deployment/pkg/builditem/UberJarIgnoredResourceBuildItemTest.java new file mode 100644 index 0000000000000..a29373de19fa0 --- /dev/null +++ b/core/test-extension/deployment/src/test/java/io/quarkus/deployment/pkg/builditem/UberJarIgnoredResourceBuildItemTest.java @@ -0,0 +1,52 @@ +package io.quarkus.deployment.pkg.builditem; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.net.URL; +import java.util.Collections; +import java.util.List; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.bootstrap.model.AppArtifact; +import io.quarkus.runtime.annotations.QuarkusMain; +import io.quarkus.test.QuarkusProdModeTest; + +class UberJarIgnoredResourceBuildItemTest { + + @RegisterExtension + static final QuarkusProdModeTest runner = new QuarkusProdModeTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addAsManifestResource("application.properties", "microprofile-config.properties") + .addClass(UberJarMain.class)) + .setApplicationName("uber-jar-ignored") + .setApplicationVersion("0.1-SNAPSHOT") + .setRun(true) + .setExpectExit(true) + .overrideConfigKey("quarkus.package.type", "uber-jar") + .setForcedDependencies( + Collections.singletonList( + // META-INF/cxf/cxf.fixml should be present in the cxf-rt-transports-http and cxf-core JARs + new AppArtifact("org.apache.cxf", "cxf-rt-transports-http", "3.4.3"))); + + @Test + public void testResourceWasIgnored() throws IOException { + assertThat(runner.getStartupConsoleOutput()).contains("RESOURCES: 0"); + assertThat(runner.getExitCode()).isZero(); + } + + @QuarkusMain + public static class UberJarMain { + + public static void main(String[] args) throws IOException { + List resources = Collections + .list(UberJarMain.class.getClassLoader().getResources("META-INF/cxf/cxf.fixml")); + System.out.println("RESOURCES: " + resources.size()); + } + + } +} diff --git a/core/test-extension/deployment/src/test/java/io/quarkus/deployment/pkg/builditem/UberJarMergedResourceBuildItemTest.java b/core/test-extension/deployment/src/test/java/io/quarkus/deployment/pkg/builditem/UberJarMergedResourceBuildItemTest.java new file mode 100644 index 0000000000000..4491a952a92fc --- /dev/null +++ b/core/test-extension/deployment/src/test/java/io/quarkus/deployment/pkg/builditem/UberJarMergedResourceBuildItemTest.java @@ -0,0 +1,78 @@ +package io.quarkus.deployment.pkg.builditem; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.bootstrap.model.AppArtifact; +import io.quarkus.runtime.annotations.QuarkusMain; +import io.quarkus.test.QuarkusProdModeTest; + +class UberJarMergedResourceBuildItemTest { + + @RegisterExtension + static final QuarkusProdModeTest runner = new QuarkusProdModeTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addAsManifestResource("application.properties", "microprofile-config.properties") + .addClass(UberJarMain.class)) + .setApplicationName("uber-jar-merged") + .setApplicationVersion("0.1-SNAPSHOT") + .setRun(true) + .setExpectExit(true) + .overrideConfigKey("quarkus.package.type", "uber-jar") + .setForcedDependencies( + Collections.singletonList( + // META-INF/cxf/bus-extensions.txt should be present in the cxf-rt-transports-http and cxf-core JARs + new AppArtifact("org.apache.cxf", "cxf-rt-transports-http", "3.4.3"))); + + @Test + public void testResourceWasMerged() throws IOException { + assertThat(runner.getStartupConsoleOutput()).contains("RESOURCES: 1", + "org.apache.cxf.transport.http.HTTPTransportFactory::true", + "org.apache.cxf.transport.http.HTTPWSDLExtensionLoader::true:true", + "org.apache.cxf.transport.http.policy.HTTPClientAssertionBuilder::true:true", + "org.apache.cxf.transport.http.policy.HTTPServerAssertionBuilder::true:true", + "org.apache.cxf.transport.http.policy.NoOpPolicyInterceptorProvider::true:true", + "org.apache.cxf.bus.managers.PhaseManagerImpl:org.apache.cxf.phase.PhaseManager:true", + "org.apache.cxf.bus.managers.WorkQueueManagerImpl:org.apache.cxf.workqueue.WorkQueueManager:true", + "org.apache.cxf.bus.managers.CXFBusLifeCycleManager:org.apache.cxf.buslifecycle.BusLifeCycleManager:true", + "org.apache.cxf.bus.managers.ServerRegistryImpl:org.apache.cxf.endpoint.ServerRegistry:true", + "org.apache.cxf.bus.managers.EndpointResolverRegistryImpl:org.apache.cxf.endpoint.EndpointResolverRegistry:true", + "org.apache.cxf.bus.managers.HeaderManagerImpl:org.apache.cxf.headers.HeaderManager:true", + "org.apache.cxf.service.factory.FactoryBeanListenerManager::true", + "org.apache.cxf.bus.managers.ServerLifeCycleManagerImpl:org.apache.cxf.endpoint.ServerLifeCycleManager:true", + "org.apache.cxf.bus.managers.ClientLifeCycleManagerImpl:org.apache.cxf.endpoint.ClientLifeCycleManager:true", + "org.apache.cxf.bus.resource.ResourceManagerImpl:org.apache.cxf.resource.ResourceManager:true", + "org.apache.cxf.catalog.OASISCatalogManager:org.apache.cxf.catalog.OASISCatalogManager:true", + "org.apache.cxf.common.util.ASMHelperImpl:org.apache.cxf.common.util.ASMHelper:true", + "org.apache.cxf.common.spi.ClassLoaderProxyService:org.apache.cxf.common.spi.ClassLoaderService:true"); + assertThat(runner.getExitCode()).isZero(); + } + + @QuarkusMain + public static class UberJarMain { + + public static void main(String[] args) throws IOException { + List resources = Collections + .list(UberJarMain.class.getClassLoader().getResources("META-INF/cxf/bus-extensions.txt")); + System.out.println("RESOURCES: " + resources.size()); + try (InputStream is = resources.get(0).openStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { + reader.lines().forEach(System.out::println); + } + } + + } +} From 3f079855681195af7bf96d149ee6c779a4f16d88 Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Mon, 10 May 2021 09:20:51 -0300 Subject: [PATCH 0013/2077] Integer::new is deprecated --- .../src/test/java/io/quarkus/extest/ConfiguredBeanTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/test-extension/deployment/src/test/java/io/quarkus/extest/ConfiguredBeanTest.java b/core/test-extension/deployment/src/test/java/io/quarkus/extest/ConfiguredBeanTest.java index dedb18a71cc75..ddb88de43866a 100644 --- a/core/test-extension/deployment/src/test/java/io/quarkus/extest/ConfiguredBeanTest.java +++ b/core/test-extension/deployment/src/test/java/io/quarkus/extest/ConfiguredBeanTest.java @@ -274,7 +274,7 @@ public void testConversionUsingConvertWith() { Assertions.assertFalse(configuredBean.getRunTimeConfig().objectBoolean); Assertions.assertEquals(2, configuredBean.getRunTimeConfig().primitiveInteger); Assertions.assertEquals(9, configuredBean.getRunTimeConfig().objectInteger); - List oneToNine = IntStream.range(1, 10).mapToObj(Integer::new).collect(Collectors.toList()); + List oneToNine = IntStream.range(1, 10).mapToObj(Integer::valueOf).collect(Collectors.toList()); Assertions.assertEquals(oneToNine, configuredBean.getRunTimeConfig().oneToNine); List mapValues = new ArrayList<>(Arrays.asList(1, 2)); List actualMapValues = new ArrayList<>(configuredBean.getRunTimeConfig().mapOfNumbers.values()); From 8a456bafcd0be33b0000124cb8c0ea66bb8d238f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 May 2021 21:11:31 +0000 Subject: [PATCH 0014/2077] Bump awssdk.version from 2.16.59 to 2.16.60 Bumps `awssdk.version` from 2.16.59 to 2.16.60. Updates `software.amazon.awssdk:bom` from 2.16.59 to 2.16.60 - [Release notes](https://github.com/aws/aws-sdk-java-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-java-v2/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java-v2/compare/2.16.59...2.16.60) Updates `apache-client` from 2.16.59 to 2.16.60 Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 5944f65a7e0b6..81b8801197767 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -151,7 +151,7 @@ 3.8.0 1.3.1 2.9.0 - 2.16.59 + 2.16.60 2.38.1 1.4.2 1.4.32 From d50150d129c4e444e7fe464de0fb197faaf21464 Mon Sep 17 00:00:00 2001 From: Andy Damevin Date: Mon, 10 May 2021 14:53:06 +0200 Subject: [PATCH 0015/2077] Improve adding extension xp in all tooling --- .../handlers/AddExtensionsCommandHandler.java | 38 ++++++++++++--- .../devtools/project/buildfile/BuildFile.java | 48 +++++++++++++------ .../project/buildfile/MavenBuildFile.java | 18 ++++++- .../buildfile/MavenProjectBuildFile.java | 20 +++++++- .../extensions/ExtensionInstallPlan.java | 24 +++++++++- .../project/extensions/ExtensionManager.java | 35 +++++++++++--- 6 files changed, 150 insertions(+), 33 deletions(-) diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/AddExtensionsCommandHandler.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/AddExtensionsCommandHandler.java index 732161a32671b..67d6964e4227f 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/AddExtensionsCommandHandler.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/AddExtensionsCommandHandler.java @@ -1,6 +1,7 @@ package io.quarkus.devtools.commands.handlers; import static io.quarkus.devtools.commands.AddExtensions.EXTENSION_MANAGER; +import static io.quarkus.devtools.messagewriter.MessageIcons.ERROR_ICON; import static io.quarkus.devtools.messagewriter.MessageIcons.NOK_ICON; import io.quarkus.devtools.commands.AddExtensions; @@ -42,17 +43,38 @@ public QuarkusCommandOutcome execute(QuarkusCommandInvocation invocation) throws invocation.getQuarkusProject().getExtensionManager()); try { ExtensionInstallPlan extensionInstallPlan = planInstallation(invocation, extensionsQuery); - if (extensionInstallPlan.isNotEmpty()) { + if (extensionInstallPlan.isInstallable()) { final InstallResult result = extensionManager.install(extensionInstallPlan); - result.getInstalled() + result.getInstalledPlatforms() + .forEach(a -> invocation.log() + .info(MessageIcons.OK_ICON + " Platform " + a.getGroupId() + ":" + a.getArtifactId() + + " has been installed")); + result.getInstalledManagedExtensions() .forEach(a -> invocation.log() .info(MessageIcons.OK_ICON + " Extension " + a.getGroupId() + ":" + a.getArtifactId() + " has been installed")); + result.getInstalledIndependentExtensions() + .forEach(a -> invocation.log() + .info(MessageIcons.OK_ICON + " Extension " + a.getGroupId() + ":" + a.getArtifactId() + ":" + + a.getVersion() + + " has been installed")); + result.getAlreadyInstalled() + .forEach(a -> invocation.log() + .info(MessageIcons.NOOP_ICON + " Extension " + a.getGroupId() + ":" + a.getArtifactId() + + " was already installed")); return new QuarkusCommandOutcome(true).setValue(AddExtensions.OUTCOME_UPDATED, result.isSourceUpdated()); + } else if (!extensionInstallPlan.getUnmatchedKeywords().isEmpty()) { + invocation.log() + .info(ERROR_ICON + " Nothing installed because keyword(s) '" + + String.join("', '", extensionInstallPlan.getUnmatchedKeywords()) + + "' were not matched in the catalog."); + } else { + invocation.log() + .info(NOK_ICON + " The provided keyword(s) did not match any extension from the catalog."); } } catch (MultipleExtensionsFoundException m) { StringBuilder sb = new StringBuilder(); - sb.append(NOK_ICON + " Multiple extensions matching '").append(m.getKeyword()).append("'"); + sb.append(ERROR_ICON + " Multiple extensions matching '").append(m.getKeyword()).append("'"); m.getExtensions() .forEach(extension -> sb.append(System.lineSeparator()).append(" * ") .append(extension.managementKey())); @@ -68,12 +90,14 @@ public QuarkusCommandOutcome execute(QuarkusCommandInvocation invocation) throws public ExtensionInstallPlan planInstallation(QuarkusCommandInvocation invocation, Collection keywords) throws IOException { + if (keywords.isEmpty()) { + return ExtensionInstallPlan.EMPTY; + } final ExtensionCatalog catalog = invocation.getExtensionsCatalog(); final String quarkusCore = catalog.getQuarkusCoreVersion(); final Collection importedPlatforms = invocation.getQuarkusProject().getExtensionManager() .getInstalledPlatforms(); ExtensionInstallPlan.Builder builder = ExtensionInstallPlan.builder(); - boolean multipleKeywords = keywords.size() > 1; for (String keyword : keywords) { int countColons = StringUtils.countMatches(keyword, ":"); // Check if it's just groupId:artifactId @@ -87,9 +111,9 @@ public ExtensionInstallPlan planInstallation(QuarkusCommandInvocation invocation continue; } List listed = listInternalExtensions(quarkusCore, keyword, catalog.getExtensions()); - if (listed.size() != 1 && multipleKeywords) { - // No extension found for this keyword. Return empty immediately - return ExtensionInstallPlan.EMPTY; + if (listed.isEmpty()) { + // No extension found for this keyword. + builder.addUnmatchedKeyword(keyword); } // If it's a pattern allow multiple results // See https://github.com/quarkusio/quarkus/issues/11086#issuecomment-666360783 diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/BuildFile.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/BuildFile.java index 0e352cef901bc..019692b474be7 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/BuildFile.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/BuildFile.java @@ -32,33 +32,44 @@ public BuildFile(final Path projectDirPath, ExtensionCatalog catalog) { @Override public final InstallResult install(Collection coords) throws IOException { - this.refreshData(); - final Collection installed = withoutAlreadyInstalled(coords); - installed.forEach(e -> addDependency(e, e.getVersion() == null)); - this.writeToDisk(); - return new InstallResult(installed); + final ExtensionInstallPlan.Builder builder = ExtensionInstallPlan.builder(); + for (ArtifactCoords coord : coords) { + if ("pom".equals(coord.getType())) { + builder.addPlatform(coord); + } else if (coord.getVersion() == null) { + builder.addManagedExtension(coord); + } else { + builder.addIndependentExtension(coord); + } + } + return install(builder.build()); } @Override public InstallResult install(ExtensionInstallPlan plan) throws IOException { - List installed = new ArrayList<>(); - for (ArtifactCoords platform : withoutAlreadyInstalled(plan.getPlatforms())) { + this.refreshData(); + List installedManagedExtensions = new ArrayList<>(); + List installedIndependentExtensions = new ArrayList<>(); + List installedPlatforms = new ArrayList<>(); + final Set alreadyInstalled = alreadyInstalled(plan.toCollection()); + for (ArtifactCoords platform : withoutAlreadyInstalled(alreadyInstalled, plan.getPlatforms())) { if (addDependency(platform, false)) { - installed.add(platform); + installedPlatforms.add(platform); } } - for (ArtifactCoords managedExtension : withoutAlreadyInstalled(plan.getManagedExtensions())) { + for (ArtifactCoords managedExtension : withoutAlreadyInstalled(alreadyInstalled, plan.getManagedExtensions())) { if (addDependency(managedExtension, true)) { - installed.add(managedExtension); + installedManagedExtensions.add(managedExtension); } } - for (ArtifactCoords independentExtension : withoutAlreadyInstalled(plan.getIndependentExtensions())) { + for (ArtifactCoords independentExtension : withoutAlreadyInstalled(alreadyInstalled, plan.getIndependentExtensions())) { if (addDependency(independentExtension, false)) { - installed.add(independentExtension); + installedIndependentExtensions.add(independentExtension); } } writeToDisk(); - return new InstallResult(installed); + return new InstallResult(installedPlatforms, installedManagedExtensions, installedIndependentExtensions, + alreadyInstalled); } @Override @@ -88,8 +99,17 @@ public final UninstallResult uninstall(Collection keys) throws IOEx return new UninstallResult(uninstalled); } - private Collection withoutAlreadyInstalled(Collection extensions) throws IOException { + private Set alreadyInstalled(Collection extensions) throws IOException { final Set existingKeys = getDependenciesKeys(); + return extensions.stream() + .distinct() + .filter(a -> existingKeys.contains(a.getKey())) + .map(ArtifactCoords::getKey) + .collect(Collectors.toSet()); + } + + private Collection withoutAlreadyInstalled(Set existingKeys, + Collection extensions) { return extensions.stream() .distinct() .filter(a -> !existingKeys.contains(a.getKey())) diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/MavenBuildFile.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/MavenBuildFile.java index 6686625bc3d77..6c5e33ac9ac82 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/MavenBuildFile.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/MavenBuildFile.java @@ -81,7 +81,13 @@ protected boolean addDependency(ArtifactCoords coords, boolean managed) { if (model.getDependencies() .stream() .noneMatch(thisDep -> d.getManagementKey().equals(thisDep.getManagementKey()))) { - model.addDependency(d); + final int index = getIndexToAddExtension(); + if (index >= 0) { + model.getDependencies().add(index, d); + } else { + model.getDependencies().add(d); + } + return true; } } @@ -152,6 +158,16 @@ private Model getModel() { }); } + private int getIndexToAddExtension() { + final List dependencies = getModel().getDependencies(); + for (int i = 0; i < dependencies.size(); i++) { + if ("test".equals(dependencies.get(i).getScope())) { + return i; + } + } + return -1; + } + private Model initModel() throws IOException { if (!hasProjectFile(BuildTool.MAVEN.getDependenciesFile())) { return null; diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/MavenProjectBuildFile.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/MavenProjectBuildFile.java index fa28530883175..66383ce637f21 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/MavenProjectBuildFile.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/MavenProjectBuildFile.java @@ -221,7 +221,13 @@ protected boolean addDependency(ArtifactCoords coords, boolean managed) { } else if (model().getDependencies() .stream() .noneMatch(thisDep -> d.getManagementKey().equals(thisDep.getManagementKey()))) { - model().addDependency(d); + final int index = getIndexToAddExtension(); + if (index >= 0) { + model().getDependencies().add(index, d); + } else { + model().getDependencies().add(d); + } + // it could still be a transitive dependency or inherited from the parent if (!getDependencies().contains(coords)) { getDependencies().add(coords); @@ -241,8 +247,8 @@ protected void removeDependency(ArtifactKey key) throws IOException { i.remove(); break; } - model().getDependencies().removeIf(d -> Objects.equals(toKey(d), key)); } + model().getDependencies().removeIf(d -> Objects.equals(toKey(d), key)); } } @@ -293,6 +299,16 @@ protected String getProperty(String propertyName) { protected void refreshData() { } + private int getIndexToAddExtension() { + final List dependencies = model().getDependencies(); + for (int i = 0; i < dependencies.size(); i++) { + if ("test".equals(dependencies.get(i).getScope())) { + return i; + } + } + return -1; + } + private Model model() { return model; } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/extensions/ExtensionInstallPlan.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/extensions/ExtensionInstallPlan.java index aefc0da8ac59e..ef8ed352e86e3 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/extensions/ExtensionInstallPlan.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/extensions/ExtensionInstallPlan.java @@ -1,6 +1,7 @@ package io.quarkus.devtools.project.extensions; import io.quarkus.maven.ArtifactCoords; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashSet; @@ -9,6 +10,7 @@ public class ExtensionInstallPlan { public static final ExtensionInstallPlan EMPTY = new ExtensionInstallPlan( + Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet()); @@ -16,13 +18,16 @@ public class ExtensionInstallPlan { private final Set platforms; private final Set managedExtensions; private final Set independentExtensions; + private final Collection unmatchedKeywords; private ExtensionInstallPlan(Set platforms, Set managedExtensions, - Set independentExtensions) { + Set independentExtensions, + Collection unmatchedKeywords) { this.platforms = platforms; this.managedExtensions = managedExtensions; this.independentExtensions = independentExtensions; + this.unmatchedKeywords = unmatchedKeywords; } public boolean isNotEmpty() { @@ -30,6 +35,10 @@ public boolean isNotEmpty() { || !this.independentExtensions.isEmpty(); } + public boolean isInstallable() { + return isNotEmpty() && unmatchedKeywords.isEmpty(); + } + /** * @return a {@link Collection} of all extensions contained in this object */ @@ -63,12 +72,17 @@ public Collection getIndependentExtensions() { return independentExtensions; } + public Collection getUnmatchedKeywords() { + return unmatchedKeywords; + } + @Override public String toString() { return "InstallRequest{" + "platforms=" + platforms + ", managedExtensions=" + managedExtensions + ", independentExtensions=" + independentExtensions + + ", unmatchedKeywords=" + unmatchedKeywords + '}'; } @@ -81,9 +95,10 @@ public static class Builder { private final Set platforms = new LinkedHashSet<>(); private final Set extensionsInPlatforms = new LinkedHashSet<>(); private final Set independentExtensions = new LinkedHashSet<>(); + private final Collection unmatchedKeywords = new ArrayList<>(); public ExtensionInstallPlan build() { - return new ExtensionInstallPlan(platforms, extensionsInPlatforms, independentExtensions); + return new ExtensionInstallPlan(platforms, extensionsInPlatforms, independentExtensions, unmatchedKeywords); } public Builder addIndependentExtension(ArtifactCoords artifactCoords) { @@ -101,6 +116,11 @@ public Builder addPlatform(ArtifactCoords artifactCoords) { return this; } + public Builder addUnmatchedKeyword(String unmatchedKeyword) { + this.unmatchedKeywords.add(unmatchedKeyword); + return this; + } + public boolean hasExtensionInPlatform() { return !this.extensionsInPlatforms.isEmpty(); } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/extensions/ExtensionManager.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/extensions/ExtensionManager.java index bd717483fee47..08d9a5fbf918f 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/extensions/ExtensionManager.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/extensions/ExtensionManager.java @@ -76,7 +76,7 @@ default boolean isInstalled(ArtifactKey key) throws IOException { /** * This is going to uninstall/remove all the specified extensions from the project build file(s). * - * This is ignoring the {@link Extension} version + * This is ignoring the version * * @param keys the set of {@link ArtifactKey} for the extensions to uninstall * @return the {@link InstallResult} @@ -85,18 +85,39 @@ default boolean isInstalled(ArtifactKey key) throws IOException { UninstallResult uninstall(Collection keys) throws IOException; class InstallResult { - private final Collection installed; + private final Collection installedPlatforms; + private final Collection installedManagedExtensions; + private final Collection installedIndependentExtensions; + private final Collection alreadyInstalled; + + public InstallResult(Collection installedPlatforms, + Collection installedManagedExtensions, + Collection installedIndependentExtensions, Collection alreadyInstalled) { + this.installedPlatforms = installedPlatforms; + this.installedManagedExtensions = installedManagedExtensions; + this.installedIndependentExtensions = installedIndependentExtensions; + this.alreadyInstalled = alreadyInstalled; + } + + public Collection getInstalledManagedExtensions() { + return installedManagedExtensions; + } + + public Collection getInstalledIndependentExtensions() { + return installedIndependentExtensions; + } - public InstallResult(Collection installed) { - this.installed = installed; + public Collection getInstalledPlatforms() { + return installedPlatforms; } - public Collection getInstalled() { - return installed; + public Collection getAlreadyInstalled() { + return alreadyInstalled; } public boolean isSourceUpdated() { - return installed.size() > 0; + return !installedPlatforms.isEmpty() || !installedManagedExtensions.isEmpty() + || !installedIndependentExtensions.isEmpty(); } } From 1b21de4de026d4693ad38218a3302c311c337469 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 May 2021 21:33:07 +0000 Subject: [PATCH 0016/2077] Bump awaitility from 4.0.3 to 4.1.0 Bumps [awaitility](https://github.com/awaitility/awaitility) from 4.0.3 to 4.1.0. - [Release notes](https://github.com/awaitility/awaitility/releases) - [Changelog](https://github.com/awaitility/awaitility/blob/master/changelog.txt) - [Commits](https://github.com/awaitility/awaitility/commits/awaitility-4.1.0) Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 5944f65a7e0b6..9f2b5ab95fa60 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -159,7 +159,7 @@ 2.1.2 0.10.0 3.0.1 - 4.0.3 + 4.1.0 1.6.5 1.0.9 5.11.0.202103091610-r From de4cf75f96ab1abcbaf672598ba135c7c32b32d3 Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Wed, 21 Apr 2021 16:37:17 +1000 Subject: [PATCH 0017/2077] Use the watch service when possible Using the watch service on Linux allows for tests to run instantly after the file is saved. Other platforms don't have a useful watch service implementation, so we still use polling for these platforms. --- .../dev/RuntimeUpdatesProcessor.java | 138 +++++++--- .../dev/filewatch/FileChangeCallback.java | 18 ++ .../dev/filewatch/FileChangeEvent.java | 63 +++++ .../WatchServiceFileSystemWatcher.java | 246 ++++++++++++++++++ .../dev/FileSystemWatcherTestCase.java | 192 ++++++++++++++ .../quarkus/dev/testing/TestScanningLock.java | 27 ++ .../io/quarkus/test/QuarkusDevModeTest.java | 35 ++- 7 files changed, 667 insertions(+), 52 deletions(-) create mode 100644 core/deployment/src/main/java/io/quarkus/deployment/dev/filewatch/FileChangeCallback.java create mode 100644 core/deployment/src/main/java/io/quarkus/deployment/dev/filewatch/FileChangeEvent.java create mode 100644 core/deployment/src/main/java/io/quarkus/deployment/dev/filewatch/WatchServiceFileSystemWatcher.java create mode 100644 core/deployment/src/test/java/io/quarkus/deployment/dev/FileSystemWatcherTestCase.java create mode 100644 core/devmode-spi/src/main/java/io/quarkus/dev/testing/TestScanningLock.java diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java index 7d2b8f22416ae..23c99aafa6213 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java @@ -20,10 +20,12 @@ import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.FileTime; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -52,6 +54,9 @@ import io.quarkus.bootstrap.runner.Timing; import io.quarkus.changeagent.ClassChangeAgent; +import io.quarkus.deployment.dev.filewatch.FileChangeCallback; +import io.quarkus.deployment.dev.filewatch.FileChangeEvent; +import io.quarkus.deployment.dev.filewatch.WatchServiceFileSystemWatcher; import io.quarkus.deployment.dev.testing.TestListener; import io.quarkus.deployment.dev.testing.TestRunner; import io.quarkus.deployment.dev.testing.TestSupport; @@ -59,8 +64,10 @@ import io.quarkus.dev.spi.DevModeType; import io.quarkus.dev.spi.HotReplacementContext; import io.quarkus.dev.spi.HotReplacementSetup; +import io.quarkus.dev.testing.TestScanningLock; public class RuntimeUpdatesProcessor implements HotReplacementContext, Closeable { + public static final boolean IS_LINUX = System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("linux"); private static final Logger log = Logger.getLogger(RuntimeUpdatesProcessor.class); @@ -100,7 +107,6 @@ public class RuntimeUpdatesProcessor implements HotReplacementContext, Closeable private final BiConsumer, ClassScanResult> restartCallback; private final BiConsumer copyResourceNotification; private final BiFunction classTransformers; - private Timer timer; private final ReentrantLock scanLock = new ReentrantLock(); /** @@ -114,6 +120,9 @@ public class RuntimeUpdatesProcessor implements HotReplacementContext, Closeable private volatile Boolean instrumentationEnabled; private volatile boolean liveReloadEnabled = true; + private WatchServiceFileSystemWatcher testClassChangeWatcher; + private Timer testClassChangeTimer; + public RuntimeUpdatesProcessor(Path applicationRoot, DevModeContext context, QuarkusCompiler compiler, DevModeType devModeType, BiConsumer, ClassScanResult> restartCallback, BiConsumer copyResourceNotification, @@ -141,9 +150,17 @@ public void testsEnabled() { @Override public void testsDisabled() { synchronized (RuntimeUpdatesProcessor.this) { - if (timer != null) { - timer.cancel(); - timer = null; + if (testClassChangeWatcher != null) { + try { + testClassChangeWatcher.close(); + } catch (IOException e) { + //ignore + } + testClassChangeWatcher = null; + } + if (testClassChangeTimer != null) { + testClassChangeTimer.cancel(); + testClassChangeTimer = null; } } } @@ -170,47 +187,87 @@ public List getSourcesDir() { .collect(toList()); } - private Timer startTestScanningTimer() { + private void startTestScanningTimer() { synchronized (this) { - if (timer == null) { - timer = new Timer("Test Compile Timer", true); - timer.schedule(new TimerTask() { - @Override - public void run() { - periodicTestCompile(); + if (testClassChangeWatcher == null && testClassChangeTimer == null) { + if (IS_LINUX) { + //note that this is only used for notifications that something has changed, + //this triggers the same file scan as the polling approach + //this is not as efficient as it could be, but saves having two separate code paths + testClassChangeWatcher = new WatchServiceFileSystemWatcher("Quarkus Test Watcher", true); + FileChangeCallback callback = new FileChangeCallback() { + @Override + public void handleChanges(Collection changes) { + //sometimes changes come through as two events + //which can cause problems for our CI tests + //and cause unessesary runs. + //we add a half second delay for CI tests, to make sure this does not cause + //problems + try { + if (context.isTest()) { + Thread.sleep(500); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + periodicTestCompile(); + } + }; + for (DevModeContext.ModuleInfo module : context.getAllModules()) { + for (String path : module.getMain().getSourcePaths()) { + testClassChangeWatcher.watchPath(new File(path), callback); + } + if (module.getMain().getResourcePath() != null) { + testClassChangeWatcher.watchPath(new File(module.getMain().getResourcePath()), callback); + } + } + for (String path : context.getApplicationRoot().getTest().get().getSourcePaths()) { + testClassChangeWatcher.watchPath(new File(path), callback); } - }, 1, 1000); + if (context.getApplicationRoot().getTest().get().getResourcePath() != null) { + testClassChangeWatcher + .watchPath(new File(context.getApplicationRoot().getTest().get().getResourcePath()), callback); + } + periodicTestCompile(); + } else { + testClassChangeTimer = new Timer("Test Compile Timer", true); + testClassChangeTimer.schedule(new TimerTask() { + @Override + public void run() { + periodicTestCompile(); + } + }, 1, 1000); + } } } - return timer; } private void periodicTestCompile() { - //noop if already scanning - if (scanLock.tryLock()) { - try { - ClassScanResult changedTestClassResult = compileTestClasses(); - ClassScanResult changedApp = checkForChangedClasses(compiler, DevModeContext.ModuleInfo::getMain, false, test); - Set filesChanged = checkForFileChange(DevModeContext.ModuleInfo::getMain, test); - boolean configFileRestartNeeded = filesChanged.stream().map(watchedFilePaths::get) - .anyMatch(Boolean.TRUE::equals); - ClassScanResult merged = ClassScanResult.merge(changedTestClassResult, changedApp); - if (configFileRestartNeeded) { - if (compileProblem != null) { - testSupport.getTestRunner().testCompileFailed(compileProblem); - } else { - testSupport.getTestRunner().runTests(null); - } - } else if (merged.isChanged()) { - if (compileProblem != null) { - testSupport.getTestRunner().testCompileFailed(compileProblem); - } else { - testSupport.getTestRunner().runTests(merged); - } + scanLock.lock(); + TestScanningLock.lockForTests(); + try { + ClassScanResult changedTestClassResult = compileTestClasses(); + ClassScanResult changedApp = checkForChangedClasses(compiler, DevModeContext.ModuleInfo::getMain, false, test); + Set filesChanged = checkForFileChange(DevModeContext.ModuleInfo::getMain, test); + boolean configFileRestartNeeded = filesChanged.stream().map(watchedFilePaths::get) + .anyMatch(Boolean.TRUE::equals); + ClassScanResult merged = ClassScanResult.merge(changedTestClassResult, changedApp); + if (configFileRestartNeeded) { + if (compileProblem != null) { + testSupport.getTestRunner().testCompileFailed(compileProblem); + } else { + testSupport.getTestRunner().runTests(null); + } + } else if (merged.isChanged()) { + if (compileProblem != null) { + testSupport.getTestRunner().testCompileFailed(compileProblem); + } else { + testSupport.getTestRunner().runTests(merged); } - } finally { - scanLock.unlock(); } + } finally { + TestScanningLock.unlockForTests(); + scanLock.unlock(); } } @@ -856,10 +913,13 @@ public static void setLastStartIndex(IndexView lastStartIndex) { @Override public void close() throws IOException { - if (timer != null) { - timer.cancel(); - } compiler.close(); + if (testClassChangeWatcher != null) { + testClassChangeWatcher.close(); + } + if (testClassChangeTimer != null) { + testClassChangeTimer.cancel(); + } } private Map expandGlobPattern(Path root, Path configFile) { diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/filewatch/FileChangeCallback.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/filewatch/FileChangeCallback.java new file mode 100644 index 0000000000000..faa0557d7e039 --- /dev/null +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/filewatch/FileChangeCallback.java @@ -0,0 +1,18 @@ +package io.quarkus.deployment.dev.filewatch; + +import java.util.Collection; + +/** + * Callback for file system change events + * + */ +public interface FileChangeCallback { + + /** + * Method that is invoked when file system changes are detected. + * + * @param changes the file system changes + */ + void handleChanges(final Collection changes); + +} diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/filewatch/FileChangeEvent.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/filewatch/FileChangeEvent.java new file mode 100644 index 0000000000000..64b50afef6468 --- /dev/null +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/filewatch/FileChangeEvent.java @@ -0,0 +1,63 @@ +package io.quarkus.deployment.dev.filewatch; + +import java.io.File; + +/** + * The event object that is fired when a file system change is detected. + * + * @see WatchServiceFileSystemWatcher + * + */ +public class FileChangeEvent { + + private final File file; + private final Type type; + + /** + * Construct a new instance. + * + * @param file the file which is being watched + * @param type the type of event that was encountered + */ + public FileChangeEvent(File file, Type type) { + this.file = file; + this.type = type; + } + + /** + * Get the file which was being watched. + * + * @return the file which was being watched + */ + public File getFile() { + return file; + } + + /** + * Get the type of event. + * + * @return the type of event + */ + public Type getType() { + return type; + } + + /** + * Watched file event types. More may be added in the future. + */ + public static enum Type { + /** + * A file was added in a directory. + */ + ADDED, + /** + * A file was removed from a directory. + */ + REMOVED, + /** + * A file was modified in a directory. + */ + MODIFIED, + } + +} diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/filewatch/WatchServiceFileSystemWatcher.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/filewatch/WatchServiceFileSystemWatcher.java new file mode 100644 index 0000000000000..2a8f365ebc677 --- /dev/null +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/filewatch/WatchServiceFileSystemWatcher.java @@ -0,0 +1,246 @@ +package io.quarkus.deployment.dev.filewatch; + +import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; +import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; +import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; + +import java.io.File; +import java.io.IOException; +import java.nio.file.ClosedWatchServiceException; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardWatchEventKinds; +import java.nio.file.WatchEvent; +import java.nio.file.WatchKey; +import java.nio.file.WatchService; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; + +import org.jboss.logging.Logger; + +/** + * File system watcher service based on JDK7 {@link WatchService}. Instantiating this class will create a new thread, + * that will run until {@link #close()} is called. + * + * NOTE: this was copied from Xnio, it provides more functionality than we currently need. + * + */ +public class WatchServiceFileSystemWatcher implements Runnable { + + private static final Logger log = Logger.getLogger(WatchServiceFileSystemWatcher.class); + + private static final AtomicInteger threadIdCounter = new AtomicInteger(0); + + private WatchService watchService; + private final Map files = Collections.synchronizedMap(new HashMap()); + private final Map pathDataByKey = Collections + .synchronizedMap(new IdentityHashMap()); + + private volatile boolean stopped = false; + private final Thread watchThread; + + public WatchServiceFileSystemWatcher(final String name, final boolean daemon) { + try { + watchService = FileSystems.getDefault().newWatchService(); + } catch (IOException e) { + throw new RuntimeException(e); + } + watchThread = new Thread(this, name + " - " + threadIdCounter); + watchThread.setDaemon(daemon); + watchThread.start(); + } + + @Override + public void run() { + while (!stopped) { + try { + final WatchKey key = watchService.take(); + if (key != null) { + try { + PathData pathData = pathDataByKey.get(key); + if (pathData != null) { + final List results = new ArrayList(); + List> events = key.pollEvents(); + final Set addedFiles = new HashSet(); + final Set deletedFiles = new HashSet(); + for (WatchEvent event : events) { + Path eventPath = (Path) event.context(); + File targetFile = ((Path) key.watchable()).resolve(eventPath).toFile(); + FileChangeEvent.Type type; + + if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) { + type = FileChangeEvent.Type.ADDED; + addedFiles.add(targetFile); + if (targetFile.isDirectory()) { + try { + addWatchedDirectory(pathData, targetFile); + } catch (IOException e) { + log.debugf(e, "Could not add watched directory %s", targetFile); + } + } + } else if (event.kind() == StandardWatchEventKinds.ENTRY_MODIFY) { + type = FileChangeEvent.Type.MODIFIED; + } else if (event.kind() == StandardWatchEventKinds.ENTRY_DELETE) { + type = FileChangeEvent.Type.REMOVED; + deletedFiles.add(targetFile); + } else { + continue; + } + results.add(new FileChangeEvent(targetFile, type)); + } + key.pollEvents().clear(); + + //now we need to prune the results, to remove duplicates + //e.g. if the file is modified after creation we only want to + //show the create event + Iterator it = results.iterator(); + while (it.hasNext()) { + FileChangeEvent event = it.next(); + if (event.getType() == FileChangeEvent.Type.MODIFIED) { + if (addedFiles.contains(event.getFile()) && + deletedFiles.contains(event.getFile())) { + // XNIO-344 + // All file change events (ADDED, REMOVED and MODIFIED) occurred here. + // This happens when an updated file is moved from the different + // filesystems or the directory having different project quota on Linux. + // ADDED and REMOVED events will be removed in the latter conditional branching. + // So, this MODIFIED event needs to be kept for the file change notification. + continue; + } + if (addedFiles.contains(event.getFile()) || + deletedFiles.contains(event.getFile())) { + it.remove(); + } + } else if (event.getType() == FileChangeEvent.Type.ADDED) { + if (deletedFiles.contains(event.getFile())) { + it.remove(); + } + } else if (event.getType() == FileChangeEvent.Type.REMOVED) { + if (addedFiles.contains(event.getFile())) { + it.remove(); + } + } + } + + if (!results.isEmpty()) { + for (FileChangeCallback callback : pathData.callbacks) { + invokeCallback(callback, results); + } + } + } + } finally { + //if the key is no longer valid remove it from the files list + if (!key.reset()) { + files.remove(key.watchable()); + } + } + } + } catch (InterruptedException e) { + //ignore + } catch (ClosedWatchServiceException cwse) { + // the watcher service is closed, so no more waiting on events + // @see https://developer.jboss.org/message/911519 + break; + } + } + } + + public synchronized void watchPath(File file, FileChangeCallback callback) { + try { + PathData data = files.get(file); + if (data == null) { + Set allDirectories = doScan(file).keySet(); + Path path = Paths.get(file.toURI()); + data = new PathData(path); + for (File dir : allDirectories) { + addWatchedDirectory(data, dir); + } + files.put(file, data); + } + data.callbacks.add(callback); + + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void addWatchedDirectory(PathData data, File dir) throws IOException { + Path path = Paths.get(dir.toURI()); + WatchKey key = path.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); + pathDataByKey.put(key, data); + data.keys.add(key); + } + + public synchronized void unwatchPath(File file, final FileChangeCallback callback) { + PathData data = files.get(file); + if (data != null) { + data.callbacks.remove(callback); + if (data.callbacks.isEmpty()) { + files.remove(file); + for (WatchKey key : data.keys) { + key.cancel(); + pathDataByKey.remove(key); + } + + } + } + } + + public void close() throws IOException { + this.stopped = true; + watchThread.interrupt(); + if (watchService != null) { + watchService.close(); + } + } + + private static Map doScan(File file) { + final Map results = new HashMap(); + + final Deque toScan = new ArrayDeque(); + toScan.add(file); + while (!toScan.isEmpty()) { + File next = toScan.pop(); + if (next.isDirectory()) { + results.put(next, next.lastModified()); + File[] list = next.listFiles(); + if (list != null) { + for (File f : list) { + toScan.push(new File(f.getAbsolutePath())); + } + } + } + } + return results; + } + + private static void invokeCallback(FileChangeCallback callback, List results) { + try { + callback.handleChanges(results); + } catch (Exception e) { + log.error("Failed to invoke watch callback", e); + } + } + + private class PathData { + final Path path; + final List callbacks = new ArrayList(); + final List keys = new ArrayList(); + + private PathData(Path path) { + this.path = path; + } + } + +} diff --git a/core/deployment/src/test/java/io/quarkus/deployment/dev/FileSystemWatcherTestCase.java b/core/deployment/src/test/java/io/quarkus/deployment/dev/FileSystemWatcherTestCase.java new file mode 100644 index 0000000000000..86cde04e6bed6 --- /dev/null +++ b/core/deployment/src/test/java/io/quarkus/deployment/dev/FileSystemWatcherTestCase.java @@ -0,0 +1,192 @@ +package io.quarkus.deployment.dev; + +import static io.quarkus.deployment.dev.filewatch.FileChangeEvent.Type.ADDED; +import static io.quarkus.deployment.dev.filewatch.FileChangeEvent.Type.MODIFIED; +import static io.quarkus.deployment.dev.filewatch.FileChangeEvent.Type.REMOVED; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Collection; +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.quarkus.deployment.dev.filewatch.FileChangeCallback; +import io.quarkus.deployment.dev.filewatch.FileChangeEvent; +import io.quarkus.deployment.dev.filewatch.WatchServiceFileSystemWatcher; + +/** + * Test file system watcher, non poll based + */ +public class FileSystemWatcherTestCase { + public static final String DIR_NAME = "/fileSystemWatcherTest"; + public static final String EXISTING_FILE_NAME = "a.txt"; + public static final String EXISTING_DIR = "existingDir"; + + private final BlockingDeque> results = new LinkedBlockingDeque<>(); + private final BlockingDeque> secondResults = new LinkedBlockingDeque<>(); + + File rootDir; + File existingSubDir; + + @BeforeEach + public void setup() throws Exception { + //this can be slow on other OS's + //as it just relies on polling + Assumptions.assumeTrue(RuntimeUpdatesProcessor.IS_LINUX); + + rootDir = new File(System.getProperty("java.io.tmpdir") + DIR_NAME); + deleteRecursive(rootDir); + + rootDir.mkdirs(); + File existing = new File(rootDir, EXISTING_FILE_NAME); + touchFile(existing); + existingSubDir = new File(rootDir, EXISTING_DIR); + existingSubDir.mkdir(); + existing = new File(existingSubDir, EXISTING_FILE_NAME); + touchFile(existing); + } + + private static void touchFile(File existing) throws IOException { + FileOutputStream out = new FileOutputStream(existing); + try { + out.write(("data" + System.currentTimeMillis()).getBytes()); + out.flush(); + } finally { + out.close(); + } + } + + @AfterEach + public void after() { + if (rootDir != null) { + deleteRecursive(rootDir); + } + } + + @Test + public void testFileSystemWatcher() throws Exception { + WatchServiceFileSystemWatcher watcher = new WatchServiceFileSystemWatcher("test", true); + try { + watcher.watchPath(rootDir, new FileChangeCallback() { + @Override + public void handleChanges(Collection changes) { + results.add(changes); + } + }); + watcher.watchPath(rootDir, new FileChangeCallback() { + @Override + public void handleChanges(Collection changes) { + secondResults.add(changes); + } + }); + //first add a file + File added = new File(rootDir, "newlyAddedFile.txt").getAbsoluteFile(); + touchFile(added); + checkResult(added, ADDED); + added.setLastModified(500); + checkResult(added, MODIFIED); + added.delete(); + Thread.sleep(1); + checkResult(added, REMOVED); + added = new File(existingSubDir, "newSubDirFile.txt"); + touchFile(added); + checkResult(added, ADDED); + added.setLastModified(500); + checkResult(added, MODIFIED); + added.delete(); + Thread.sleep(1); + checkResult(added, REMOVED); + File existing = new File(rootDir, EXISTING_FILE_NAME); + existing.delete(); + Thread.sleep(1); + checkResult(existing, REMOVED); + File newDir = new File(rootDir, "newlyCreatedDirectory"); + newDir.mkdir(); + checkResult(newDir, ADDED); + added = new File(newDir, "newlyAddedFileInNewlyAddedDirectory.txt").getAbsoluteFile(); + touchFile(added); + checkResult(added, ADDED); + added.setLastModified(500); + checkResult(added, MODIFIED); + added.delete(); + Thread.sleep(1); + checkResult(added, REMOVED); + + } finally { + watcher.close(); + } + + } + + private void checkResult(File file, FileChangeEvent.Type type) throws InterruptedException { + Collection results = this.results.poll(20, TimeUnit.SECONDS); + Collection secondResults = this.secondResults.poll(20, TimeUnit.SECONDS); + Assertions.assertNotNull(results); + Assertions.assertEquals(1, results.size()); + Assertions.assertEquals(1, secondResults.size()); + FileChangeEvent res = results.iterator().next(); + FileChangeEvent res2 = secondResults.iterator().next(); + + //sometime OS's will give a MODIFIED event before the REMOVED one + //We consume these events here + long endTime = System.currentTimeMillis() + 10000; + while (type == REMOVED + && (res.getType() == MODIFIED || res2.getType() == MODIFIED) + && System.currentTimeMillis() < endTime) { + FileChangeEvent[] nextEvents = consumeEvents(); + res = nextEvents[0]; + res2 = nextEvents[1]; + } + + //sometime OS's will give a MODIFIED event on its parent folder before the ADDED one + //We consume these events here + endTime = System.currentTimeMillis() + 10000; + while (type == ADDED + && (res.getType() == MODIFIED || res2.getType() == MODIFIED) + && (res.getFile().equals(file.getParentFile()) || res2.getFile().equals(file.getParentFile())) + && !file.isDirectory() + && System.currentTimeMillis() < endTime) { + FileChangeEvent[] nextEvents = consumeEvents(); + res = nextEvents[0]; + res2 = nextEvents[1]; + } + + Assertions.assertEquals(file, res.getFile()); + Assertions.assertEquals(type, res.getType()); + Assertions.assertEquals(file, res2.getFile()); + Assertions.assertEquals(type, res2.getType()); + } + + private FileChangeEvent[] consumeEvents() throws InterruptedException { + FileChangeEvent[] nextEvents = new FileChangeEvent[2]; + Collection results = this.results.poll(1, TimeUnit.SECONDS); + Collection secondResults = this.secondResults.poll(1, TimeUnit.SECONDS); + Assertions.assertNotNull(results); + Assertions.assertNotNull(secondResults); + Assertions.assertEquals(1, results.size()); + Assertions.assertEquals(1, secondResults.size()); + nextEvents[0] = results.iterator().next(); + nextEvents[1] = secondResults.iterator().next(); + + return nextEvents; + } + + public static void deleteRecursive(final File file) { + File[] files = file.listFiles(); + if (files != null) { + for (File f : files) { + deleteRecursive(f); + } + } + file.delete(); + } + +} diff --git a/core/devmode-spi/src/main/java/io/quarkus/dev/testing/TestScanningLock.java b/core/devmode-spi/src/main/java/io/quarkus/dev/testing/TestScanningLock.java new file mode 100644 index 0000000000000..d3b3ae73f89f8 --- /dev/null +++ b/core/devmode-spi/src/main/java/io/quarkus/dev/testing/TestScanningLock.java @@ -0,0 +1,27 @@ +package io.quarkus.dev.testing; + +import java.util.concurrent.locks.ReentrantLock; + +/** + * lock that is used to prevent scanning while the dev mode test is updating classes + * + * This prevents races in the continuous testing tests. It's not an ideal solution + * but its the only one I can think of at the moment. + */ +public class TestScanningLock { + + private static final ReentrantLock lock = new ReentrantLock(); + + /** + * There is a race when testing this, where you can see the intermediate empty state of the + * file, or where the file time changes twice. Dev mode tests hold this lock during modification + * to avoid the race. + */ + public static void lockForTests() { + lock.lock(); + } + + public static void unlockForTests() { + lock.unlock(); + } +} diff --git a/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusDevModeTest.java b/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusDevModeTest.java index b8822a779974b..343349e0daf06 100644 --- a/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusDevModeTest.java +++ b/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusDevModeTest.java @@ -52,6 +52,7 @@ import io.quarkus.deployment.dev.DevModeMain; import io.quarkus.deployment.util.FileUtil; import io.quarkus.dev.appstate.ApplicationStateNotification; +import io.quarkus.dev.testing.TestScanningLock; import io.quarkus.runtime.LaunchMode; import io.quarkus.runtime.configuration.ProfileManager; import io.quarkus.runtime.util.ClassPathUtils; @@ -582,24 +583,30 @@ public QuarkusDevModeTest setCommandLineArgs(String[] commandLineArgs) { } void modifyFile(String name, Function mutator, Path path) { - AtomicBoolean found = new AtomicBoolean(false); - try (Stream sources = Files.walk(path)) { - sources.forEach(s -> { - if (s.endsWith(name)) { - found.set(true); - modifyPath(mutator, path, s); - } - }); - } catch (IOException e) { - throw new UncheckedIOException(e); - } + TestScanningLock.lockForTests(); + try { + AtomicBoolean found = new AtomicBoolean(false); + try (Stream sources = Files.walk(path)) { + sources.forEach(s -> { + if (s.endsWith(name)) { + found.set(true); + modifyPath(mutator, path, s); + } + }); + } catch (IOException e) { + throw new UncheckedIOException(e); + } - if (!found.get()) { - throw new IllegalArgumentException("File " + name + " was not part of the test application"); + if (!found.get()) { + throw new IllegalArgumentException("File " + name + " was not part of the test application"); + } + } finally { + TestScanningLock.unlockForTests(); } } private void modifyPath(Function mutator, Path sourceDirectory, Path input) { + TestScanningLock.lockForTests(); try { long old = modTime(input); long oldSrc = modTime(sourceDirectory); @@ -619,6 +626,8 @@ private void modifyPath(Function mutator, Path sourceDirectory, sleepForFileChanges(input, old); } catch (IOException e) { throw new UncheckedIOException(e); + } finally { + TestScanningLock.unlockForTests(); } } From f6f0efac9493ff9d0ae0e6764533b4b3e8c6fb29 Mon Sep 17 00:00:00 2001 From: SaumyaSingh1 Date: Tue, 11 May 2021 14:54:28 +0530 Subject: [PATCH 0018/2077] Fix qute TemplateException in RESTEasy Reactive Endpoint Page --- .../deployment/src/main/resources/dev-templates/endpoints.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/resources/dev-templates/endpoints.html b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/resources/dev-templates/endpoints.html index 5dfeafef8e61a..c90890f1ef2c1 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/resources/dev-templates/endpoints.html +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/resources/dev-templates/endpoints.html @@ -43,7 +43,7 @@
REST Resources
{/if} {/for}
Static Resources
- {#for resource in info:staticResourceInfo.resourceMap.get("/").children} + {#for resource in info:staticResourceInfo.resourceMap.get("/").children.orEmpty}
{#if resource.isFolder} From bfcb7e79af63cd98e9b8f5ae6096f9dff5c0e1ba Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Tue, 11 May 2021 11:31:16 +0200 Subject: [PATCH 0019/2077] Log presence of Docker at DEBUG level, not INFO Logging at INFO level is unnecessary verbose given it will be displayed for each build. --- .../src/main/java/io/quarkus/deployment/IsDockerWorking.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/IsDockerWorking.java b/core/deployment/src/main/java/io/quarkus/deployment/IsDockerWorking.java index 2881c540dff34..11b9286fa9bb6 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/IsDockerWorking.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/IsDockerWorking.java @@ -42,7 +42,7 @@ public boolean getAsBoolean() { try { OutputFilter filter = new OutputFilter(); if (ExecUtil.exec(new File("."), filter, "docker", "version", "--format", "'{{.Server.Version}}'")) { - LOGGER.info("Docker daemon found. Version:" + filter.getOutput()); + LOGGER.debugf("Docker daemon found. Version: %s", filter.getOutput()); return true; } else { if (!silent) { From 008762f33dddc7252b1d623196373109d118fc1c Mon Sep 17 00:00:00 2001 From: Clement Escoffier Date: Wed, 14 Apr 2021 08:51:14 +0200 Subject: [PATCH 0020/2077] Rewrite of the configurations guides --- .../asciidoc/config-extending-support.adoc | 354 +++++++ docs/src/main/asciidoc/config-mappings.adoc | 669 +++++++++++++ docs/src/main/asciidoc/config-reference.adoc | 880 +++++------------- docs/src/main/asciidoc/config-yaml.adoc | 206 ++++ docs/src/main/asciidoc/config.adoc | 100 +- .../main/asciidoc/images/config-sources.png | Bin 0 -> 35194 bytes .../src/main/asciidoc/writing-extensions.adoc | 1 + 7 files changed, 1540 insertions(+), 670 deletions(-) create mode 100644 docs/src/main/asciidoc/config-extending-support.adoc create mode 100644 docs/src/main/asciidoc/config-mappings.adoc create mode 100644 docs/src/main/asciidoc/config-yaml.adoc create mode 100644 docs/src/main/asciidoc/images/config-sources.png diff --git a/docs/src/main/asciidoc/config-extending-support.adoc b/docs/src/main/asciidoc/config-extending-support.adoc new file mode 100644 index 0000000000000..710860fd0ff38 --- /dev/null +++ b/docs/src/main/asciidoc/config-extending-support.adoc @@ -0,0 +1,354 @@ +//// +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 +//// += Extending Configuration Support + +include::./attributes.adoc[] + +:numbered: +:sectnums: +:sectnumlevels: 4 +:toc: + +[[custom-config-source]] +== Custom `ConfigSource` + +It's possible to create a custom `ConfigSource` as specified in +link:https://github.com/eclipse/microprofile-config/blob/master/spec/src/main/asciidoc/configsources.asciidoc#custom-configsources-via-configsourceprovider[MicroProfile Config]. + +With a Custom `ConfigSource` it is possible to read additional configuration values and add them to the `Config` +instance in a defined ordinal. This allows overriding values from other sources or falling back to other values. + +image::config-sources.png[] + +A custom `ConfigSource` requires an implementation of `org.eclipse.microprofile.config.spi.ConfigSource` or +`org.eclipse.microprofile.config.spi.ConfigSourceProvider`. Each implementation requires registration via +the https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/ServiceLoader.html[ServiceLoader] mechanism, either in +`META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource` or +`META-INF/services/org.eclipse.microprofile.config.spi.ConfigSourceProvider` files. + +=== Example + +Consider a simple in-memory `ConfigSource`: + +.org.acme.config.InMemoryConfigSource +[source,java] +---- +package org.acme.config; + +import org.eclipse.microprofile.config.spi.ConfigSource; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public class InMemoryConfigSource implements ConfigSource { + private static final Map configuration = new HashMap<>(); + + static { + configuration.put("my.prop", "1234"); + } + + @Override + public int getOrdinal() { + return 275; + } + + @Override + public Set getPropertyNames() { + return configuration.keySet(); + } + + @Override + public String getValue(final String propertyName) { + return configuration.get(propertyName); + } + + @Override + public String getName() { + return InMemoryConfigSource.class.getSimpleName(); + } +} +---- + +And registration in: + +.META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource +[source,properties] +---- +org.acme.config.InMemoryConfigSource +---- + +The `InMemoryConfigSource` will be ordered between the `.env` source, and the `application.properties` source due to +the `275` ordinal: + + +|=== +|ConfigSource |Ordinal + +|System Properties +|400 + +|Environment Variables from System +|300 + +|Environment Variables from `.env` file +|295 + +|InMemoryConfigSource +|275 + +|`application.properties` from `/config` +|260 + +|`application.properties` from application +|250 + +|`microprofile-config.properties` from application +|100 +|=== + +In this case, `my.prop` from `InMemoryConfigSource` will only be used if the config engine is unable to find a value +in xref:config-reference.adoc#system-properties[System Properties], +xref:config-reference.adoc#environment-variables[Environment Variables from System] or +xref:config-reference.adoc#env-file[Environment Variables from .env file] in this order. + +[[config-source-factory]] +== `ConfigSourceFactory` + +Another way to create a `ConfigSource` is via the https://github.com/smallrye/smallrye-config[SmallRye Config] +`io.smallrye.config.ConfigSourceFactory` API. The difference between the +https://github.com/smallrye/smallrye-config[SmallRye Config] factory and the standard way to create a `ConfigSource` as +specified in +link:https://github.com/eclipse/microprofile-config/blob/master/spec/src/main/asciidoc/configsources.asciidoc#custom-configsources-via-configsourceprovider[MicroProfile Config], +is the factory ability to provide a context with access to the available configuration. + +Each implementation of `io.smallrye.config.ConfigSourceFactory` requires registration via +the https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/ServiceLoader.html[ServiceLoader] +mechanism in the `META-INF/services/io.smallrye.config.ConfigSourceFactory` file. + +=== Example + +Consider: + +.org.acme.config.URLConfigSourceFactory +[source,java] +---- +package org.acme.config; + +import java.util.Collections; +import java.util.OptionalInt; + +import org.eclipse.microprofile.config.spi.ConfigSource; + +import io.smallrye.config.ConfigSourceContext; +import io.smallrye.config.ConfigSourceFactory; +import io.smallrye.config.ConfigValue; +import io.smallrye.config.PropertiesConfigSource; + +public class URLConfigSourceFactory implements ConfigSourceFactory { + @Override + public Iterable getConfigSources(final ConfigSourceContext context) { + final ConfigValue value = context.getValue("config.url"); + if (value == null || value.getValue() == null) { + return Collections.emptyList(); + } + + try { + return Collections.singletonList(new PropertiesConfigSource(new URL(value.getValue()))); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public OptionalInt getPriority() { + return OptionalInt.of(290); + } +} +---- + +And registration in: + +.META-INF/services/io.smallrye.config.ConfigSourceFactory +[source,properties] +---- +org.acme.config.URLConfigSourceFactory +---- + +By implementing `io.smallrye.config.ConfigSourceFactory`, a list of `ConfigSource` may be provided via the +`Iterable getConfigSources(ConfigSourceContext context)` method. The `ConfigSourceFactory` may also +assign a priority by overriding the method `OptionalInt getPriority()`. The priority values is used to sort +multiple `io.smallrye.config.ConfigSourceFactory` (if found). + +IMPORTANT: `io.smallrye.config.ConfigSourceFactory` priority does not affect the `ConfigSource` ordinal. These are +sorted independently. + +When the Factory is initializing, the provided `ConfigSourceContext` may call the method +`ConfigValue getValue(String name)`. This method looks up configuration names in all ``ConfigSource``s that were already +initialized by the `Config` instance, including sources with lower ordinals than the ones defined in the +`ConfigSourceFactory`. The `ConfigSource` list provided by a `ConfigSourceFactory` is not taken into consideration to +configure other sources produced by a lower priority `ConfigSourceFactory`. + +[[custom-converter]] +== Custom `Converter` + +It is possible to create a custom `Converter` type as specified by +link:https://github.com/eclipse/microprofile-config/blob/master/spec/src/main/asciidoc/converters.asciidoc#adding-custom-converters[MicroProfile Config]. + +A custom `Converter` requires an implementation of `org.eclipse.microprofile.config.spi.Converter`. Each implementation +requires registration via the https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/ServiceLoader.html[ServiceLoader] +mechanism in the `META-INF/services/org.eclipse.microprofile.config.spi.Converter` file. Consider: + +[source,java] +---- +package org.acme.config; + +public class MicroProfileCustomValue { + + private final int number; + + public MicroProfileCustomValue(int number) { + this.number = number; + } + + public int getNumber() { + return number; + } +} +---- + +The corresponding converter will look similar to the one below. + +[source,java] +---- +package org.acme.config; + +import org.eclipse.microprofile.config.spi.Converter; + +public class MicroProfileCustomValueConverter implements Converter { + + @Override + public MicroProfileCustomValue convert(String value) { + return new MicroProfileCustomValue(Integer.parseInt(value)); + } +} +---- + +NOTE: The custom converter class must be `public`, must have a `public` constructor with no arguments, and must not be +`abstract`. + +The custom configuration type converts the configuration value automatically: + +[source,java] +---- +@ConfigProperty(name = "configuration.value.name") +MicroProfileCustomValue value; +---- + +=== Converter priority + +The `javax.annotation.Priority` annotation overrides the `Converter` priority and change converters precedence to fine +tune the execution order. By default, if no `@Priority` is specified by the `Converter`, the converter is registered +with a priority of `100`. Consider: + +[source,java] +---- +package org.acme.config; + +import javax.annotation.Priority; +import org.eclipse.microprofile.config.spi.Converter; + +@Priority(150) +public class MyCustomConverter implements Converter { + + @Override + public MicroProfileCustomValue convert(String value) { + + final int secretNumber; + if (value.startsFrom("OBF:")) { + secretNumber = Integer.parseInt(SecretDecoder.decode(value)); + } else { + secretNumber = Integer.parseInt(value); + } + + return new MicroProfileCustomValue(secretNumber); + } +} +---- + +Since it converts the same value type (`MicroProfileCustomValue`) and has a priority of `150`, it will be used +instead of a `MicroProfileCustomValueConverter` which has a default priority of `100`. + +NOTE: All Quarkus core converters use the priority value of `200`. To override any Quarkus specific converter, the +priority value should be higher than `200`. + +[[config-interceptors]] +== Config Interceptors + +https://github.com/smallrye/smallrye-config[SmallRye Config] provides an interceptor chain that hooks into the +configuration values resolution. This is useful to implement features like +xref:config-reference.adoc#profiles[Profiles], +xref:config-reference.adoc#property-expressions[Property Expressions], +or just logging to find out where the config value was loaded from. + +An interceptor requires an implementation of `io.smallrye.config.ConfigSourceInterceptor`. Each implementation +requires registration via the https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/ServiceLoader.html[ServiceLoader] +mechanism in the `META-INF/services/io.smallrye.config.ConfigSourceInterceptor` file. + +The `io.smallrye.config.ConfigSourceInterceptor` is able to intercept the resolution of a configuration name with the +method `ConfigValue getValue(ConfigSourceInterceptorContext context, String name)`. The `ConfigSourceInterceptorContext` +is used to proceed with the interceptor chain. The chain can be short-circuited by returning an instance of +`io.smallrye.config.ConfigValue`. The `ConfigValue` objects hold information about the key name, value, config source +origin and ordinal. + +NOTE: The interceptor chain is applied before any conversion is performed on the configuration value. + +Interceptors may also be created with an implementation of `io.smallrye.config.ConfigSourceInterceptorFactory`. Each +implementation requires registration via the https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/ServiceLoader.html[ServiceLoader] +mechanism in the `META-INF/services/io.smallrye.config.ConfigSourceInterceptorFactory` file. + +The `ConfigSourceInterceptorFactory` may initialize an interceptor with access to the current chain +(so it can be used to configure the interceptor and retrieve configuration values) and set the priority. + +=== Example + +.org.acme.config.LoggingConfigSourceInterceptor +[source,java] +---- +package org.acme.config; + +import javax.annotation.Priority; + +import io.smallrye.config.ConfigSourceInterceptor; +import io.smallrye.config.ConfigLogging; + +@Priority(Priorities.LIBRARY + 200) +public class LoggingConfigSourceInterceptor implements ConfigSourceInterceptor { + private static final long serialVersionUID = 367246512037404779L; + + @Override + public ConfigValue getValue(final ConfigSourceInterceptorContext context, final String name) { + ConfigValue configValue = doLocked(() -> context.proceed(name)); + if (configValue != null) { + ConfigLogging.log.lookup(configValue.getName(), configValue.getLocation(), configValue.getValue()); + } else { + ConfigLogging.log.notFound(name); + } + return configValue; + } +} +---- + +And registration in: + +.META-INF/services/io.smallrye.config.ConfigSourceInterceptor +[source,properties] +---- +org.acme.config.LoggingConfigSourceInterceptor +---- + +The `LoggingConfigSourceInterceptor` logs looks up configuration names in the provided logging platform. The log +information includes config name and value, the config source origin and location if exists. diff --git a/docs/src/main/asciidoc/config-mappings.adoc b/docs/src/main/asciidoc/config-mappings.adoc new file mode 100644 index 0000000000000..a0252762ad3a1 --- /dev/null +++ b/docs/src/main/asciidoc/config-mappings.adoc @@ -0,0 +1,669 @@ +//// +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 +//// += Mapping configuration to objects + +include::./attributes.adoc[] + +:numbered: +:sectnums: +:sectnumlevels: 4 +:toc: + +With config mappings it is possible to group multiple configuration properties in a single interface that +share the same prefix. + +[[config-mappings]] +== `@ConfigMapping` + +A config mapping requires an interface with minimal metadata configuration and annotated with the +`@io.smallrye.config.ConfigMapping` annotation. + +[source,java] +---- +@ConfigMapping(prefix = "server") +interface Server { + String host(); + + int port(); +} +---- + +The `Server` interface is able to map configuration properties with the name `server.host` into the `Server.host()` +method and `server.port` into `Server.port()` method. The configuration property name to look up is built from the +prefix, and the method name with `.` (dot) as the separator. + +NOTE: If a mapping fails to match a configuration property a `NoSuchElementException` is thrown, unless the mapped +element is an `Optional`. + +=== Retrieval + +A config mapping interface can be injected into any CDI aware bean: + +[source,java] +---- +class BusinessBean { + @Inject + Server server; + + public void businessMethod() { + String host = server.host(); + } +} +---- + +In non-CDI contexts, use the API `io.smallrye.config.SmallRyeConfig#getConfigMapping` to retrieve the config mapping +instance: + +[source,java] +---- +SmallRyeConfig config = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class); +Server server = config.getConfigMapping(Server.class); +---- + +=== Nested groups + +A nested mapping provides a way to subgroup other config properties: + +[source,java] +---- +@ConfigMapping(prefix = "server") +public interface Server { + String host(); + + int port(); + + Log log(); + + interface Log { + boolean enabled(); + + String suffix(); + + boolean rotate(); + } +} +---- + +.application.properties +[source,properties] +---- +server.host=localhost +server.port=8080 +server.log.enabled=true +server.log.suffix=.log +server.log.rotate=false +---- + +The method name of a mapping group acts as sub-namespace to the configurations properties. + +=== Overriding property names + +==== `@WithName` + +If a method name, or a property name do not match with each other, the `@WithName` annotation can override the method +name mapping and use the name supplied in the annotation: + +[source,java] +---- +@ConfigMapping(prefix = "server") +interface Server { + @WithName("name") + String host(); + + int port(); +} +---- + +.application.properties +[source,properties] +---- +server.name=localhost +server.port=8080 +---- + +==== `@WithParentName` + +The `@WithParent` annotation allows to configurations mapping to inherit its container name, simplifying the +configuration property name required to match the mapping: + +[source,java] +---- +interface Server { + @WithParentName + ServerHostAndPort hostAndPort(); + + @WithParentName + ServerInfo info(); +} + +interface ServerHostAndPort { + String host(); + + int port(); +} + +interface ServerInfo { + String name(); +} +---- + +.application.properties +[source,properties] +---- +server.host=localhost +server.port=8080 +server.name=konoha +---- + +Without the `@WithParentName` the method `name()` requires the configuration property `server.info.name`. Because we use +`@WithParentName`, the `info()` mapping will inherit the parent name from `Server` and `name()` maps to `server.name` +instead. + +==== NamingStrategy + +Method names in camelCase map to kebab-case property names: + +[source,java] +---- +@ConfigMapping(prefix = "server") +interface Server { + String theHost(); + + int thePort(); +} +---- + +.application.properties +[source,properties] +---- +server.the-host=localhost +server.the-port=8080 +---- + +The mapping strategy can be adjusted by setting `namingStrategy` value in the `@ConfigMapping` annotation: + +[source,java] +---- +@ConfigMapping(prefix = "server", namingStrategy = ConfigMapping.NamingStrategy.VERBATIM) +public interface ServerVerbatimNamingStrategy { + String theHost(); + + int thePort(); +} +---- + +.application.properties +[source,properties] +---- +server.theHost=localhost +server.thePort=8080 +---- + +The `@ConfigMapping` annotation support the following naming stategies: + +- `KEBAB_CASE` (default) - The method name is derived by replacing case changes with a dash to map the configuration property. +- `VERBATIM` - The method name is used as is to map the configuration property. +- `SNAKE_CASE` - The method name is derived by replacing case changes with an underscore to map the configuration property. + +=== Conversions + +A config mapping class support automatic conversions of all types available for conversion in `Config`: + +[source,java] +---- +@ConfigMapping +public interface SomeTypes { + @WithName("int") + int intPrimitive(); + + @WithName("int") + Integer intWrapper(); + + @WithName("long") + long longPrimitive(); + + @WithName("long") + Long longWrapper(); + + @WithName("float") + float floatPrimitive(); + + @WithName("float") + Float floatWrapper(); + + @WithName("double") + double doublePrimitive(); + + @WithName("double") + Double doubleWrapper(); + + @WithName("char") + char charPrimitive(); + + @WithName("char") + Character charWrapper(); + + @WithName("boolean") + boolean booleanPrimitive(); + + @WithName("boolean") + Boolean booleanWrapper(); +} +---- + +.application.properties +[source,properties] +---- +int=9 +long=9999999999 +float=99.9 +double=99.99 +char=c +boolean=true +---- + +This is also valid for `Optional` and friends: + +[source,java] +---- +@ConfigMapping +public interface Optionals { + Optional server(); + + Optional optional(); + + @WithName("optional.int") + OptionalInt optionalInt(); + + interface Server { + String host(); + + int port(); + } +} +---- + +In this case, the mapping won't fail if there are not configuration properties to match the mapping. + +==== `@WithConverter` + +The `@WithConverter` annotation provides a way to set a `Converter` to use in a specific mapping: + +[source,java] +---- +@ConfigMapping +public interface Converters { + @WithConverter(FooBarConverter.class) + String foo(); +} + +public static class FooBarConverter implements Converter { + @Override + public String convert(final String value) { + return "bar"; + } +} +---- + +.application.properties +[source,properties] +---- +foo=foo +---- + +A call to `Converters.foo()` results in the value `bar`. + +==== Collections ==== + +A config mapping is also able to map collections types `List` and `Set`: + +[source,java] +---- +@ConfigMapping(prefix = "server") +public interface ServerCollections { + Set environments(); + + interface Environment { + String name(); + + List apps(); + + interface App { + String name(); + + List services(); + + Optional> databases(); + } + } +} +---- + +.application.properties +[source,properties] +---- +server.environments[0].name=dev +server.environments[0].apps[0].name=rest +server.environments[0].apps[0].services=bookstore,registration +server.environments[0].apps[0].databases=pg,h2 +server.environments[0].apps[1].name=batch +server.environments[0].apps[1].services=stock,warehouse +---- + +The `List` or `Set` mappings can use xref:config-reference.adoc#indexed-properties[indexed properties] to map +configuration values in mapping groups. For collection with simple element types like `String`, their configuration +value is a comma separated string. + +==== Maps ==== + +A config mapping is also able to map a `Map`: + +[source,java] +---- +@ConfigMapping(prefix = "server") +public interface Server { + String host(); + + int port(); + + Map form(); +} +---- + +.application.properties +[source,properties] +---- +server.host=localhost +server.port=8080 +server.form.login-page=login.html +server.form.error-page=error.html +server.form.landing-page=index.html +---- + +The configuration property needs to specify an additional name to act as the key. In this case the `form()` `Map` will +contain three elements with the keys `login-page`, `error-page` and `landing-page`. + +=== Defaults + +The `@WithDefault` annotation allows to set a default property into a mapping (and prevent and error if the +configuration value is not available in any `ConfigSource`): + +[source,java] +---- +public interface Defaults { + @WithDefault("foo") + String foo(); + + @WithDefault("bar") + String bar(); +} +---- + +No configuration properties required. The `Defaults.foo()` will return the value `foo` and `Defaults.bar()` will return +thevalue `bar`. + +[[config-properties]] +== [.line-through]#`@ConfigProperties`# (Deprecated) + +IMPORTANT: This feature will be removed soon, please update your code base and use `@ConfigMapping` instead. + +The `@io.quarkus.arc.config.ConfigProperties` annotation is able to group multiple related configuration values in its +own class: + +[source,java] +---- +package org.acme.config; + +import io.quarkus.arc.config.ConfigProperties; +import java.util.Optional; + +@ConfigProperties(prefix = "greeting") <1> +public class GreetingConfiguration { + + private String message; + private String suffix = "!"; <2> + private Optional name; + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getSuffix() { + return suffix; + } + + public void setSuffix(String suffix) { + this.suffix = suffix; + } + + public Optional getName() { + return name; + } + + public void setName(Optional name) { + this.name = name; + } +} +---- +<1> `prefix` is optional. If not set then the prefix to be used will be determined by the class name. In this case it +would still be `greeting` (since the `Configuration` suffix is removed). If the class were named +`GreetingExtraConfiguration` then the resulting default prefix would be `greeting-extra`. +<2> `!` will be the default value if `greeting.suffix` is not set. + +Inject the `GreetingResource` with CDI `@Inject`: + +[source,java] +---- +@Inject +GreetingConfiguration greetingConfiguration; +---- + +Another alternative style provided by Quarkus is to create `GreetingConfiguration` as an interface: + +[source,java] +---- +package org.acme.config; + +import io.quarkus.arc.config.ConfigProperties; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import java.util.Optional; + +@ConfigProperties(prefix = "greeting") +public interface GreetingConfiguration { + + @ConfigProperty(name = "message") <1> + String message(); + + @ConfigProperty(defaultValue = "!") + String getSuffix(); <2> + + Optional getName(); <3> +} +---- +<1> The `@ConfigProperty` annotation is needed because the name of the configuration property that the method +corresponds does not follow the getter method naming conventions. +<2> In this case since `name` is not set, the corresponding property will be `greeting.suffix`. +<3> It is unnecessary to specify the `@ConfigProperty` annotation because the method name follows the getter method +naming conventions (`greeting.name` being the corresponding property) and no default value is required. + +When using `@ConfigProperties` on a class or an interface, if the value of one of its fields is not provided, the +application startup will fail, and a `javax.enterprise.inject.spi.DeploymentException` will be thrown. This does not +apply to `Optional` fields and fields with a default value. + +=== Additional notes on @ConfigProperties + +When using a regular class annotated with `@ConfigProperties` the class doesn't necessarily have to declare getters and +setters. Having simple public non-final fields is valid as well. + +Furthermore, the configuration classes support nested object configuration. Suppose there was a need to have an extra +layer of greeting configuration named `content` that would contain a few fields: + +[source,java] +---- +@ConfigProperties(prefix = "greeting") +public class GreetingConfiguration { + + public String message; + public String suffix = "!"; + public Optional name; + public ContentConfig content; <1> + + public static class ContentConfig { + public Integer prizeAmount; + public List recipients; + } +} +---- +<1> The name of the field (not the class name) will determine the name of the properties that are bound to the object. + +Setting the properties would occur in the normal manner: + +.application.properties +[source,properties] +---- +greeting.message = hello +greeting.name = quarkus +greeting.content.prize-amount=10 +greeting.content.recipients=Jane,John +---- + +Furthermore, classes annotated with `@ConfigProperties` can be annotated with Bean Validation annotations: + +[source,java] +---- +@ConfigProperties(prefix = "greeting") +public class GreetingConfiguration { + + @Size(min = 20) + public String message; + public String suffix = "!"; + +} +---- + +WARNING: For validation to work, the `quarkus-hibernate-validator` extension is required. + +=== Using same ConfigProperties with different prefixes + +Quarkus also supports the use of the same `@ConfigProperties` object with different prefixes for each injection point +using the `io.quarkus.arc.config.@ConfigPrefix` annotation. If `GreetingConfiguration` from above needs to be used for +both the `greeting` prefix and the `other` prefix: + +[source,java] +---- +@ConfigProperties(prefix = "greeting") +public class GreetingConfiguration { + + @Size(min = 20) + public String message; + public String suffix = "!"; + +} +---- + +[source,java] +---- +@ApplicationScoped +public class SomeBean { + + @Inject <1> + GreetingConfiguration greetingConfiguration; + + @ConfigPrefix("other") <2> + GreetingConfiguration otherConfiguration; + +} +---- +<1> At this injection point `greetingConfiguration` will use the `greeting` prefix since that is what has been defined +on `@ConfigProperties`. +<2> At this injection point `otherConfiguration` will use the `other` prefix from `@ConfigPrefix` instead of the +`greeting` prefix. Notice that in this case `@Inject` is not required. + +=== Using a list of objects + +In certain cases it might be necessary to support complex configuration structures that use a list of objects: + +[source,java] +---- +@ConfigProperties(prefix = "complex") +public class ComplexConfiguration { + public String name; + public String user; + public String password; + public List inputs; + public List outputs; + + public static class Nested { + public String user; + public String password; + } +} +---- + +Support for such use cases is only available when using YAML configuration with the `quarkus-config-yaml` extension. A +corresponding example xref:config-yaml.adoc[YAML] configuration could be: + +`application.yaml` +[source,yaml] +---- +complex: + name: defaultName + user: defaultUser + password: defaultPassword + inputs: + - user: user + password: secret + - user: otheruser + password: secret2 + outputs: + - user: someuser + password: asecret + - user: someotheruser + password: anothersecret +---- + +WARNING: A limitation of such configuration is that the types used as the generic types of the lists need to be classes +and not interfaces. + +=== Combining ConfigProperties with build time conditions + +Quarkus allows you to define conditions evaluated at build time (`@IfBuildProfile`, `@UnlessBuildProfile`, +`@IfBuildProperty` and `@UnlessBuildProperty`) to enable or not the annotations `@ConfigProperties` and `@ConfigPrefix` +which gives you a very flexible way to map your configuration. + +Let's assume that the configuration of a service is mapped thanks to a `@ConfigProperties` and you don't need this part +of the configuration for your tests as it will be mocked, in that case you can define a build time condition like in +the next example: + +`ServiceConfiguration.java` +[source,java] +---- +@UnlessBuildProfile("test") <1> +@ConfigProperties +public class ServiceConfiguration { + public String user; + public String password; +} +---- +<1> The annotation `@ConfigProperties` is considered if and only if the active profile is not `test`. + +`SomeBean.java` +[source,java] +---- +@ApplicationScoped +public class SomeBean { + + @Inject + Instance serviceConfiguration; <1> + +} +---- +<1> As the configuration of the service could be missing, we need to use `Instance` as type at +the injection point. diff --git a/docs/src/main/asciidoc/config-reference.adoc b/docs/src/main/asciidoc/config-reference.adoc index e41a982486caf..377ad403d74a9 100644 --- a/docs/src/main/asciidoc/config-reference.adoc +++ b/docs/src/main/asciidoc/config-reference.adoc @@ -12,70 +12,95 @@ include::./attributes.adoc[] :sectnumlevels: 4 :toc: -In this reference guide we're going to describe various aspects of Quarkus configuration. -A Quarkus application and Quarkus itself (core and extensions) are both configured via the same mechanism that leverages +IMPORTANT: The content of this guide has been revised and split into additional topics. Please check the <> section. + +In this reference guide we're going to describe various aspects of Quarkus configuration. A Quarkus application and +Quarkus itself (core and extensions) are both configured via the same mechanism that leverages the https://github.com/smallrye/smallrye-config[SmallRye Config] API an implementation of the -https://microprofile.io/project/eclipse/microprofile-config[MicroProfile Config] specification. Moreover, there are -several additional features which are made available by Quarkus itself. +https://microprofile.io/project/eclipse/microprofile-config[MicroProfile Config] specification. + +TIP: If you're looking for information how to make a Quarkus extension configurable then see the +<> guide. -TIP: If you're looking for information how to make a Quarkus extension configurable then see the <> guide. +[[configuration-sources]] +== Config Sources -[[configuration_sources]] -== Configuration Sources +By default, Quarkus reads configuration properties from multiple sources (by descending ordinal): -By default, Quarkus reads configuration properties from several sources (in decreasing priority): +1. (400) <> +2. (300) <> +3. (295) <> file in the current working directory +4. (260) <> in `$PWD/config/application.properties` +5. (250) <> `application.properties` in classpath +6. (100) <> +`META-INF/microprofile-config.properties` in classpath -1. <> -2. <> -3. <> placed in the current working directory -4. <> -5. <>, i.e. `src/main/resources/application.properties` +The final configuration is the aggregation of the properties defined by all these sources. A configuration property +lookup starts by the highest ordinal configuration source available and works it way down to other sources until a +match is found. This means that any configuration property may override a value just by setting a different value in a +higher ordinal config source. For example, a property configured using an environment property overrides the value +provided using the `application.properties` file. -[[system_properties]] +image::config-sources.png[] + +[[system-properties]] === System properties * for a runner jar: `java -Dquarkus.datasource.password=youshallnotpass -jar target/quarkus-app/quarkus-run.jar` * for a native executable: `./target/myapp-runner -Dquarkus.datasource.password=youshallnotpass` -[[environment_variables]] +[[environment-variables]] === Environment variables * for a runner jar: `export QUARKUS_DATASOURCE_PASSWORD=youshallnotpass ; java -jar target/quarkus-app/quarkus-run.jar` * for a native executable: `export QUARKUS_DATASOURCE_PASSWORD=youshallnotpass ; ./target/myapp-runner` -NOTE: Environment variables names are following the conversion rules of link:https://github.com/eclipse/microprofile-config/blob/master/spec/src/main/asciidoc/configsources.asciidoc#default-configsources[Eclipse MicroProfile Config]. +NOTE: Environment variables names follow the conversion rules specified by +link:https://github.com/eclipse/microprofile-config/blob/master/spec/src/main/asciidoc/configsources.asciidoc#default-configsources[MicroProfile Config]. -[[env_file]] -=== File named `.env` placed in the current working directory +[[env-file]] +=== `.env` file in the current working directory -.Example `.env` file +..env [source,properties] ---- QUARKUS_DATASOURCE_PASSWORD=youshallnotpass <1> ---- -<1> The name `QUARKUS_DATASOURCE_PASSWORD` is converted using the same rules as for <>. +<1> The name `QUARKUS_DATASOURCE_PASSWORD` the same conversion rules used for <>. -For dev mode, this file can be placed in the root of the project, but it is advised to **not** check it in to version control. +For `dev` mode, this file can be placed in the root of the project, but it is advised to **not** check it in to version +control. -NOTE: Environment variables without a configuration profile defined in `.env` file will overwrite all its related profiles in `application.properties`, e.g. `%test.application.value` is overwritten by `APPLICATION_VALUE` in `.env` file. +IMPORTANT: Environment variables in the `.env` file are not available via the `System.getenv(String)` API. -[[pwd_config_application_file]] -=== An `application.properties` file placed in `$PWD/config/` +[[application-properties-file]] +=== Quarkus Application configuration file -By placing an `application.properties` file inside a directory named `config` which resides in the directory where the application runs, any runtime properties defined in that file will override the default configuration. -Furthermore any runtime properties added to this file that were not part of the original `application.properties` file -_will also_ be taken into account. -This works in the same way for runner jar and the native executable. +The Quarkus Application configuration file is loaded from the classpath resources, for instance +`src/main/resources/application.properties`, `src/test/resources/application.properties` or from a `jar` dependency that +contains an `application.properties` entry. Additionally, the configuration file may also reside in +`$PWD/config/application.properties`. The loading starts from the config folder and then classpath order +(`application.properties` files in the application sources will have priority on the classloader loading order). -NOTE: The `config/application.properties` feature is available in development mode as well. To make use of it, `config/application.properties` needs to be placed inside the build tool's output directory (`target` for Maven and `build/classes/java/main` for Gradle). -Keep in mind however that any cleaning operation from the build tool like `mvn clean` or `gradle clean` will remove the `config` directory as well. +.`application.properties` +[source,properties] +---- +greeting.message=hello <1> +quarkus.http.port=9090 <2> +---- +<1> This is a user-defined configuration property. +<2> This is a configuration property consumed by the `quarkus-vertx-http` extension. -[[application_properties_file]] -=== An application configuration file +NOTE: The `config/application.properties` is also available in `dev` mode. The file needs to be placed inside the build +tool output directory (`target` for Maven and `build/classes/java/main` for Gradle). Keep in mind however that any +cleaning operation from the build tool like `mvn clean` or `gradle clean` will remove the `config` directory as well. -This is the main application configuration file located in `src/main/resources/application.properties`. +[[microprofile-config-properties-file]] +=== MicroProfile Config configuration file -.Example `application.properties` file +The MicroProfile Config configuration file in `src/main/resources/META-INF/microprofile-config.properties`. + +.`microprofile-config.properties` [source,properties] ---- greeting.message=hello <1> @@ -84,33 +109,35 @@ quarkus.http.port=9090 <2> <1> This is a user-defined configuration property. <2> This is a configuration property consumed by the `quarkus-vertx-http` extension. -TIP: Quarkus supports the use of <> in the `application.properties` file. +TIP: It works in the exact same way as Quarkus Application configuration file `application.properties`. Recommendation +is to use Quarkus `application.properties`. -== Embedding a configuration file inside a dependency +=== Additional Config Sources -You can embed a configuration file inside one of your dependencies by adding a `META-INF/microprofile-config.properties` configuration file to it -(this is a standard functionality of MicroProfile Config). +Quarkus provides additional extensions which cover other configuration formats and stores: -When you add this dependency to your application, its configuration properties will be merged. +* xref:config-yaml.adoc[YAML] +* xref:vault.adoc[HashiCorp Vault] +* xref:consul-config.adoc[Consul] +* xref:spring-cloud-config-client.adoc[Spring Cloud] -You can override the properties coming from it inside your `application.properties` that takes precedence over it. +TIP: It is also possible to create a xref:config-custom.adoc#custom-config-source[Custom Config Source]. -== Injecting configuration properties +== Inject -Quarkus uses https://microprofile.io/project/eclipse/microprofile-config[MicroProfile Config] annotations to inject the configuration properties in the application. +Quarkus uses https://microprofile.io/project/eclipse/microprofile-config[MicroProfile Config] annotations to inject the +configuration properties in the application. [source,java] ---- @ConfigProperty(name = "greeting.message") <1> String message; ---- -<1> You can use `@Inject @ConfigProperty` or just `@ConfigProperty`. -The `@Inject` annotation is not necessary for members annotated with `@ConfigProperty`. -This behavior differs from https://microprofile.io/project/eclipse/microprofile-config[MicroProfile Config]. +<1> You can use `@Inject @ConfigProperty` or just `@ConfigProperty`. The `@Inject` annotation is not necessary for +members annotated with `@ConfigProperty`. -NOTE: If the application attempts to inject a configuration property that is not set, an error is thrown, thus allowing you to quickly know when your configuration is complete. +NOTE: If the application attempts to inject a configuration property that is not set, an error is thrown. -.More `@ConfigProperty` Examples [source,java] ---- @ConfigProperty(name = "greeting.message") <1> @@ -126,12 +153,12 @@ Optional name; <3> <2> The default value is injected if the configuration does not provide a value for `greeting.suffix`. <3> This property is optional - an empty `Optional` is injected if the configuration does not provide a value for `greeting.name`. -== Programmatically access the configuration +TIP: Use xref:config-mappings.adoc#config-mappings[Config Mappings] to group similar configuration properties. -You can also access the configuration programmatically. -It can be handy to achieve dynamic lookup, or retrieve configured values from classes that are neither CDI beans or JAX-RS resources. +== Programmatically access -You can access the configuration programmatically using `org.eclipse.microprofile.config.ConfigProvider.getConfig()` such as in: +The `org.eclipse.microprofile.config.ConfigProvider.getConfig()` API allows to access the Config API programmatically. +This API is mostly useful in situations where CDI injection is not available. [source,java] ---- @@ -139,368 +166,179 @@ String databaseName = ConfigProvider.getConfig().getValue("database.name", Strin Optional maybeDatabaseName = ConfigProvider.getConfig().getOptionalValue("database.name", String.class); ---- -[[using_configproperties]] -== Using @ConfigProperties - -As an alternative to injecting multiple related configuration values in the way that was shown in the previous example, -users can also use the `@io.quarkus.arc.config.ConfigProperties` annotation to group these properties together. - -For the greeting properties above, a `GreetingConfiguration` class could be created like so: - -[source,java] ----- -package org.acme.config; - -import io.quarkus.arc.config.ConfigProperties; -import java.util.Optional; - -@ConfigProperties(prefix = "greeting") <1> -public class GreetingConfiguration { - - private String message; - private String suffix = "!"; <2> - private Optional name; +IMPORTANT: Do not use `System.getProperty(String)` or `System.getEnv(String)` to retrieve configuration values. These +APIs are not configuration aware and do not support the features described in this guide. - public String getMessage() { - return message; - } +[[profiles]] +== Profiles - public void setMessage(String message) { - this.message = message; - } +We often need to configure differently our application depending on the target _environment_. For example, the local +development environment may be different from the production environment. - public String getSuffix() { - return suffix; - } - - public void setSuffix(String suffix) { - this.suffix = suffix; - } - - public Optional getName() { - return name; - } - - public void setName(Optional name) { - this.name = name; - } -} ----- -<1> `prefix` is optional. If not set then the prefix to be used will be determined by the class name. In this case it would still be `greeting` (since the `Configuration` suffix is removed). If the class were named `GreetingExtraConfiguration` then the resulting default prefix would be `greeting-extra`. -<2> `!` will be the default value if `greeting.suffix` is not set. +Configuration Profiles allow for multiple configurations in the same file or separate files and select between them via +a profile name. -This class could then be injected into the `GreetingResource` using the familiar CDI `@Inject` annotation like so: - -[source,java] ----- -@Inject -GreetingConfiguration greetingConfiguration; ----- - -Another alternative style provided by Quarkus is to create `GreetingConfiguration` as an interface like so: - -[source,java] ----- -package org.acme.config; - -import io.quarkus.arc.config.ConfigProperties; -import org.eclipse.microprofile.config.inject.ConfigProperty; -import java.util.Optional; - -@ConfigProperties(prefix = "greeting") -public interface GreetingConfiguration { - - @ConfigProperty(name = "message") <1> - String message(); - - @ConfigProperty(defaultValue = "!") - String getSuffix(); <2> - - Optional getName(); <3> -} ----- -<1> The `@ConfigProperty` annotation is needed because the name of the configuration property that the method corresponds to doesn't follow the getter method naming conventions. -<2> In this case since `name` was not set, the corresponding property will be `greeting.suffix`. -<3> It is unnecessary to specify the `@ConfigProperty` annotation because the method name follows the getter method naming conventions (`greeting.name` being the corresponding property) and no default value is needed. - -When using `@ConfigProperties` on a class or an interface, if the value of one of its fields is not provided, the application startup will fail and a `javax.enterprise.inject.spi.DeploymentException` indicating the missing value information will be thrown. -This does not apply to `Optional` fields and fields with a default value. - -=== Additional notes on @ConfigProperties - -When using a regular class annotated with `@ConfigProperties` the class doesn't necessarily have to declare getters and setters. -Having simple public non-final fields is valid as well. - -Furthermore, the configuration classes support nested object configuration. Suppose there was a need to have an extra layer -of greeting configuration named `content` that would contain a few fields. This could be achieved like so: - -[source,java] ----- -@ConfigProperties(prefix = "greeting") -public class GreetingConfiguration { - - public String message; - public String suffix = "!"; - public Optional name; - public ContentConfig content; <1> - - public static class ContentConfig { - public Integer prizeAmount; - public List recipients; - } -} ----- -<1> The name of the field (not the class name) will determine the name of the properties that are bound to the object. - -Setting the properties would occur in the normal manner, for example in `application.properties` one could have: +=== Profile in the property name +To be able to set properties with the same name, each property needs to be prefixed with a percentage sign `%` followed +by the profile name and a dot `.` in the syntax `%{profile-name}.config.name`: +.application.properties [source,properties] ---- -greeting.message = hello -greeting.name = quarkus -greeting.content.prize-amount=10 -greeting.content.recipients=Jane,John ----- - -Furthermore, classes annotated with `@ConfigProperties` can be annotated with Bean Validation annotations similar to the following example: - -[source,java] ----- -@ConfigProperties(prefix = "greeting") -public class GreetingConfiguration { - - @Size(min = 20) - public String message; - public String suffix = "!"; - -} ----- - -WARNING: For validation to work, the `quarkus-hibernate-validator` extension needs to be present. - -If the validation fails with the given configuration, the application will fail to start and indicate the corresponding validation errors in the log. - -In the case of an interface being annotated with `@ConfigProperties`, the interface is allowed to extend other interfaces and methods from -the entire interface hierarchy are used to bind properties. - -=== Using same ConfigProperties with different prefixes - -Quarkus also supports the use of the same `@ConfigProperties` object with different prefixes for each injection point using the `io.quarkus.arc.config.@ConfigPrefix` annotation. -Say for example that `GreetingConfiguration` from above needs to be used for both the `greeting` prefix and the `other` prefix. -In that case the code would look like so: - -`GreetingConfiguration.java` -[source,java] +quarkus.http.port=9090 +%dev.quarkus.http.port=8181 ---- -@ConfigProperties(prefix = "greeting") -public class GreetingConfiguration { - @Size(min = 20) - public String message; - public String suffix = "!"; +The Quarkus HTTP port will be 9090. If the `dev` profile is active it will be 8181. -} ----- +Profiles in the `.env` file follow the syntax `_{PROFILE}_CONFIG_KEY=value`: -`SomeBean.java` -[source,java] +..env +[source, properties] ---- -@ApplicationScoped -public class SomeBean { - - @Inject <1> - GreetingConfiguration greetingConfiguration; - - @ConfigPrefix("other") <2> - GreetingConfiguration otherConfiguration; - -} +QUARKUS_HTTP_PORT=9090 +_DEV_QUARKUS_HTTP_PORT=8181 ---- -<1> At this injection point `greetingConfiguration` will use the `greeting` prefix since that is what has been defined on `@ConfigProperties`. -<2> At this injection point `otherConfiguration` will use the `other` prefix from `@ConfigPrefix` instead of the `greeting` prefix. Notice that in this case `@Inject` is not required. - -=== Using a list of objects -In certain cases it might be necessary to support complex configuration structures that utilize a list of objects as shown in the following example: +If a profile does not define a value for a specific attribute, the _default_ (no profile) value is used: -`ComplexConfiguration.java` -[source,java] +.application.properties +[source, properties] ---- -@ConfigProperties(prefix = "complex") -public class ComplexConfiguration { - public String name; - public String user; - public String password; - public List inputs; - public List outputs; - - public static class Nested { - public String user; - public String password; - } -} +bar=”hello” +baz=”bonjour” +%dev.bar=”hallo” ---- -Support for such use cases is only available when using YAML configuration with the `quarkus-config-yaml` extension. A corresponding example YAML configuration could be: +With the `dev` profile enabled, the property `bar` has the value `hallo`, but the property `baz` has the value +`bonjour`. If the `prod` profile is enabled, `bar` has the value `hello` (as there is no specific value for the `prod` +profile), and `baz` the value `bonjour`. -`application.yaml` -[source,yaml] ----- -complex: - name: defaultName - user: defaultUser - password: defaultPassword - inputs: - - user: user - password: secret - - user: otheruser - password: secret2 - outputs: - - user: someuser - password: asecret - - user: someotheruser - password: anothersecret ----- +=== Default Profiles -WARNING: A limitation of such configuration is that the types used as the generic types of the lists need to be classes and not interfaces. +By default, Quarkus provides three profiles, that activate automatically in certain conditions: -=== Combining ConfigProperties with build time conditions +* *dev* - Activated when in development mode (i.e. `quarkus:dev`) +* *test* - Activated when running tests +* *prod* - The default profile when not running in development or test mode -Quarkus allows you to define conditions evaluated at build time (`@IfBuildProfile`, `@UnlessBuildProfile`, `@IfBuildProperty` and `@UnlessBuildProperty`) to enable or not the annotations `@ConfigProperties` and `@ConfigPrefix` which gives you a very flexible way to map your configuration. +=== Custom Profiles -Let's assume that the configuration of a service is mapped thanks to a `@ConfigProperties` and you don't need this part of the configuration for your tests as it will be mocked, in that case you can define a build time condition like in the next example: +It is also possible to create additional profiles and activate them with the `quarkus.profile` configuration property. A +single config property with the new profile name is the only requirement: -`ServiceConfiguration.java` -[source,java] +.application.properties +[source,properties] ---- -@UnlessBuildProfile("test") <1> -@ConfigProperties -public class ServiceConfiguration { - public String user; - public String password; -} +quarkus.http.port=9090 +%staging.quarkus.http.port=9999 ---- -<1> The annotation `@ConfigProperties` is considered if and only if the active profile is not `test`. -`SomeBean.java` -[source,java] ----- -@ApplicationScoped -public class SomeBean { +Setting `quarkus.profile` to `staging` will activate the `staging` profile. - @Inject - Instance serviceConfiguration; <1> +IMPORTANT: Only a single profile may be active at a time. -} ----- -<1> As the configuration of the service could be missing, we need to use `Instance` as type at the injection point. +[NOTE] +==== +The `io.quarkus.runtime.configuration.ProfileManager#getActiveProfile` API provides a way to retrieve the active profile +programmatically. -[[configuration_profiles]] -== Configuration Profiles +Using `@ConfigProperty("quarkus.profile")` will *not* work properly. +==== -Quarkus supports the notion of configuration profiles. -These allow you to have multiple configurations in the same file and select between them via a profile name. +=== Profile aware files -The syntax for this is `%{profile}.config.key=value`. For example if I have the following: +In this case, properties for a specific profile may reside in an `application-{profile}.yaml` named file. The previous +example may be expressed as: +.application.properties [source,properties] ---- quarkus.http.port=9090 -%dev.quarkus.http.port=8181 ---- -The Quarkus HTTP port will be 9090, unless the `dev` profile is active, in which case it will be 8181. - -To use profiles in the `.env` file, you can follow a `_{PROFILE}_CONFIG_KEY=value` pattern. An equivalent of the above example in an `.env` file would be: - -[source,.env] +.application-staging.properties +[source,properties] ---- -QUARKUS_HTTP_PORT=9090 -_DEV_QUARKUS_HTTP_PORT=8181 +quarkus.http.port=9999 ---- -By default, Quarkus has three profiles, although it is possible to use as many as you like. -The default profiles are: +[NOTE] +==== +In this style, the configuration names in the profile aware file do not need to be prefixed with the profile name. +==== -* *dev* - Activated when in development mode (i.e. `quarkus:dev`) -* *test* - Activated when running tests -* *prod* - The default profile when not running in development or test mode +=== Parent Profile + +A Parent Profile adds one level of hierarchy to the current profile. The configuration `quarkus.config.profile.parent` +accepts a single profile name. -There are two ways to set a custom profile, either via the `quarkus.profile` system property or the `QUARKUS_PROFILE` -environment variable. If both are set the system property takes precedence. Note that it is not necessary to -define the names of these profiles anywhere, all that is necessary is to create a config property with the profile -name, and then set the current profile to that name. For example if I want a `staging` profile with a different HTTP port I can add the following to `application.properties`: +When the Parent Profile is active, if a property cannot be found in the current active Profile, the config lookup +fallbacks to the Parent Profile. Consider: [source,properties] ---- -quarkus.http.port=9090 -%staging.quarkus.http.port=9999 ----- +quarkus.profile=dev +quarkus.config.profile.parent=common -And then set the `QUARKUS_PROFILE` environment variable to `staging` to activate my profile. +%common.quarkus.http.port=9090 +%dev.quarkus.http.ssl-port=9443 -[NOTE] -==== -The proper way to check the active profile programmatically is to use the `getActiveProfile` method of `io.quarkus.runtime.configuration.ProfileManager`. +quarkus.http.port=8080 +quarkus.http.ssl-port=8443 +---- -Using `@ConfigProperty("quarkus.profile")` will *not* work properly. -==== +Then + +* The active profile is `dev` +* The parent profile is `common` +* `quarkus.http.port` is 9090 +* `quarkus.http.ssl-port` is 9443 === Default Runtime Profile -The default Quarkus application runtime profile is set to the profile used to build the application. -For example: +The default Quarkus runtime profile is set to the profile used to build the application: + [source,bash] ---- ./mvnw package -Pnative -Dquarkus.profile=prod-aws ./target/my-app-1.0-runner // <1> ---- -<1> The command will run with the `prod-aws` profile. This can be overridden using the `quarkus.profile` system property. - +<1> The command will run with the `prod-aws` profile. This can be overridden using the `quarkus.profile` configuration. -[[using_property_expressions]] -== Using Property Expressions +[[property-expressions]] +== Property Expressions -Quarkus supports the use of property expressions in the `application.properties` file. +Quarkus provides property expressions expansion on configuration values. An expression string is +a mix of plain strings and expression segments, which are wrapped by the sequence `${ ... }`. -These expressions are resolved when the property is read. -So if your configuration property is a build time configuration property, the property expression will be resolved at build time. -If your configuration property is overridable at runtime, the property expression will be resolved at runtime. +These expressions are resolved when the property is read. So if the configuration property is build time the property +expression will be resolved at build time. If the configuration property is overridable at runtime it will be resolved +at runtime. -You can use property expressions both for the Quarkus configuration or for your own configuration properties. - -Property expressions are defined this way: `${my-property-expression}`. - -For example, having the following property: +Consider: +.application.properties [source,properties] ---- remote.host=quarkus.io ----- -and another property defined as: - -[source,properties] ----- callable.url=https://${remote.host}/ ---- -will result in the value of the `callable.url` property being set to: - -[source,properties] ----- -callable.url=https://quarkus.io/ ----- +The resolved value of the `callable.url` property is `https://quarkus.io/`. -Another example would be defining different database servers depending on the profile used: +Another example would be defining different database servers by profile: +.application.properties [source,properties] ---- %dev.quarkus.datasource.jdbc.url=jdbc:mysql://localhost:3306/mydatabase?useSSL=false quarkus.datasource.jdbc.url=jdbc:mysql://remotehost:3306/mydatabase?useSSL=false ---- -can be simplified by having: +can be simplified to: +.application.properties [source,properties] ---- %dev.application.server=localhost @@ -509,90 +347,90 @@ application.server=remotehost quarkus.datasource.jdbc.url=jdbc:mysql://${application.server}:3306/mydatabase?useSSL=false ---- -It does result in one more line in this example but the value of `application.server` can be reused in other properties, -diminishing the possibility of typos and providing more flexibility in property definitions. +Additionally, the Expression Expansion engine supports the following segments: +* `${expression:value}` - Provides a default value after the `:` if the expansion doesn't find a value. +* `${my.prop${compose}}` - Composed expressions. Inner expressions are resolved first. +* `${my.prop}${my.prop}` - Multiple expressions. -[#combine-property-env-var] -== Combining Property Expressions and Environment Variables +If an expression cannot be expanded and no default is supplied a `NoSuchElementException` is thrown. -Quarkus also supports the combination of both property expressions and environment variables. +NOTE: Expresions lookups are performed in all config sources. The expression values and expansion values may reside in +different config sources. -Let's assume you have the following property defined in `application.properties`: +=== With Environment Variables -[source,properties] ----- -remote.host=quarkus.io ----- - -You can combine environment variables and property expressions by having a property defined as follows: +Property Expressions also work with Environment Variables. +.application.properties [source,properties] ---- +remote.host=quarkus.io application.host=${HOST:${remote.host}} ---- -This will expand the `HOST` environment variable and use the value of the property `remote.host` as the default value if `HOST` is not set. +This will expand the `HOST` environment variable and use the value of the property `remote.host` as the default value +if `HOST` is not set. + +== Clearing properties -For the purpose of this section we used the property `remote.host` we defined previously. -It has to be noted that the value could have been a fixed one such as in: +Run time properties which are optional, and which have had values set at build time or which have a default value, +may be explicitly cleared by assigning an empty string to the property. Note that this will _only_ affect +runtime properties, and will _only_ work with properties whose values are not required. +.application.properties [source,properties] ---- -application.host=${HOST:localhost} +remote.host=quarkus.io ---- -which will result in `localhost` as the default value if `HOST` is not set. +A lookup to `remote.host` with `-Dremote.host=` will throw an Exception, because the system property cleared the value. -[[configuring_quarkus]] -== Configuring Quarkus +[[indexed-properties]] +== Indexed Properties -Quarkus itself is configured via the same mechanism as your application. Quarkus reserves the `quarkus.` namespace -for its own configuration and the configuration of all of its extensions. For example to configure the HTTP server port you can set `quarkus.http.port` in -`application.properties`. All the Quarkus configuration properties are link:all-config[documented and searchable]. +A config value which contains unescaped commas may be converted to `Collection`. This works for simple cases, but it +becomes cumbersome and limited for more advanced cases. -[IMPORTANT] -==== -As mentioned above, properties prefixed with `quarkus.` are effectively reserved for configuring Quarkus itself and its extensions. -Therefore `quarkus.` should **never** be used as prefix for application specific properties. - -In the previous examples using `quarkus.message` instead of `greeting.message` would result in unexpected behavior. -==== +Indexed Properties provide a way to use indexes in config property names to map specific elements in a `Collection` +type. Since the indexed element is part of the property name and not contained in the value, this can also be used to +map complex object types as `Collectionª elements. Consider: -Quarkus does much of its configuration and bootstrap at build time and some configuration properties are read and used during the build. -These properties are _fixed at build time_ and it's not possible to change them at runtime. -You always need to repackage your application in order to reflect changes of such properties. +.application.properties +[source,properties] +---- +my.collection=dog,cat,turtle -TIP: The properties fixed at build time are marked with a lock icon (icon:lock[]) in the link:all-config[list of all configuration options]. +my.indexed.collection[0]=dog +my.indexed.collection[1]=cat +my.indexed.collection[2]=turtle +---- -However, some extensions do define properties that can be _overriden at runtime_. -A canonical example is the database URL, username and password which are only known specifically in your target environment. -This is a tradeoff as the more runtime properties are available, the less build time prework Quarkus can do. -The list of runtime properties is therefore lean. -You can override these runtime properties with the following mechanisms (in decreasing priority) using: +The indexed property syntax uses the property name and square brackets `[ ] with an index in between. -1. System properties -2. Environment variables -3. An environment file named `.env` placed in the current working directory -4. A configuration file placed in `$PWD/config/application.properties` +A call to `Config#getValues("my.collection", String.class)`, will automatically create and convert a `List` +that contains the values `dog`, `cat` and `turtle`. A call to `Config#getValues("my.indexed.collection", String.class)` +returns the exact same result. If the same property name exists in both froms (regular and indexed), the regular +value has priority. -See <> for more details. +The indexed property is sorted by their index before being added to the target `Collection`. Any gaps contained in the +indexes do not resolve to the target `Collection`, which means that the `Collection` result will store all values +without any gaps. -== Generating configuration for your application +== Generate Configuration -It is also possible to generate an example `application.properties` with all known configuration properties, to make -it easy to see what Quarkus configuration options are available. To do this, run: +It is also possible to generate an example `application.properties` with all known configuration properties: [source,bash] -- ./mvnw quarkus:generate-config -- -This will create a `src/main/resources/application.properties.example` file that contains all the config options -exposed via the extensions you currently have installed. These options are commented out, and have their default value -when applicable. For example this HTTP port config entry will appear as: - +This creates a `src/main/resources/application.properties.example` file that contains all the config options +exposed via the extensions currently present in the application. These options are commented out, and have their value +set to default swhen applicable. For example this HTTP port config entry will appear as: +.application.properties [source,properties] -- # @@ -609,257 +447,55 @@ parameter: ./mvnw quarkus:generate-config -Dfile=application.properties -- -If a config option is already present (commented or not) it will not be added, so it is safe to run this after -adding an additional extension to see what additional options have been added. - -== Clearing properties - -Run time properties which are optional, and which have had values set at build time or which have a default value, -may be explicitly cleared by assigning an empty string to the property. Note that this will _only_ affect -runtime properties, and will _only_ work with properties whose values are not required. - -The property may be cleared by setting the corresponding `application.properties` property, setting the -corresponding system property, or setting the corresponding environment variable. - -[[custom_configuration]] -== Custom Configuration +If a config option is already present it will not be added, so it is safe to run this after adding an extension to see +which configurations are available. -=== Custom configuration sources - -You can also introduce custom configuration sources in the standard MicroProfile Config manner. To -do this, you must provide a class which implements either `org.eclipse.microprofile.config.spi.ConfigSource` -or `org.eclipse.microprofile.config.spi.ConfigSourceProvider`. Create a -https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html[service file] for the -class and it will be detected and installed at application startup. - -=== Custom configuration converters - -You can also use your custom types for configuration values. This can be done by implementing `org.eclipse.microprofile.config.spi.Converter` -and adding its fully qualified class name in the `META-INF/services/org.eclipse.microprofile.config.spi.Converter` file. - -Let us assume you have a custom type like this one: - -[source,java] ----- -package org.acme.config; - -public class MicroProfileCustomValue { - - private final int number; - - public MicroProfileCustomValue(int number) { - this.number = number; - } - - public int getNumber() { - return number; - } -} ----- - -The corresponding converter will look like the one below. Please note that your custom converter class must be `public` and must have -a `public` no-argument constructor. It also must not be `abstract`. - - -[source,java] ----- -package org.acme.config; - -import org.eclipse.microprofile.config.spi.Converter; - -public class MicroProfileCustomValueConverter implements Converter { - - @Override - public MicroProfileCustomValue convert(String value) { - return new MicroProfileCustomValue(Integer.parseInt(value)); - } -} ----- - -Then you need to include the fully qualified class name of the converter in a service file `META-INF/services/org.eclipse.microprofile.config.spi.Converter`. -If you have more converters, simply add their class names in this file as well. One fully qualified class name per line, for example: - -[source] ----- -org.acme.config.MicroProfileCustomValueConverter -org.acme.config.SomeOtherConverter -org.acme.config.YetAnotherConverter ----- - -Please note that `SomeOtherConverter` and `YetAnotherConverter` were added just for demonstration purposes. If you include in this file classes -which are not available at runtime, the converters loading will fail. - -After this is done, you can use your custom type as a configuration value: - -[source,java] ----- -@ConfigProperty(name = "configuration.value.name") -MicroProfileCustomValue value; ----- - -==== Converter priority - -In some cases, you may want to use a custom converter to convert a type which is already converted -by a different converter. In such cases, you can use the `javax.annotation.Priority` annotation to -change converters precedence and make your custom converter of higher priority than the other -in the list. - -By default, if no `@Priority` can be found on a converter, it's registered with a priority of 100 -and all Quarkus core converters are registered with a priority of 200, so depending on which -converter you would like to replace, you need to set a higher value. - -To demonstrate the idea let us implement a custom converter which will take precedence over -`MicroProfileCustomValueConverter` implemented in the previous example. - -[source,java] ----- -package org.acme.config; - -import javax.annotation.Priority; -import org.eclipse.microprofile.config.spi.Converter; - -@Priority(150) -public class MyCustomConverter implements Converter { - - @Override - public MicroProfileCustomValue convert(String value) { - - final int secretNumber; - if (value.startsFrom("OBF:")) { - secretNumber = Integer.parseInt(SecretDecoder.decode(value)); - } else { - secretNumber = Integer.parseInt(value); - } - - return new MicroProfileCustomValue(secretNumber); - } -} ----- - -Since it converts the same value type (namely `MicroProfileCustomValue`) and has a priority -of 150, it will be used instead of a `MicroProfileCustomValueConverter` which has a default -priority of 100. - -NOTE: This new converter also needs to be listed in a service file, i.e. `META-INF/services/org.eclipse.microprofile.config.spi.Converter`. - -[[yaml]] -== YAML for Configuration - -=== Add YAML Config Support - -You might want to use YAML over properties for configuration. -Since link:https://github.com/smallrye/smallrye-config[SmallRye Config] brings support for YAML -configuration, Quarkus supports this as well. - -First you will need to add the Config YAML extension to your `pom.xml`: - -[source,xml] ----- - - io.quarkus - quarkus-config-yaml - ----- - -Or you can alternatively run this command in the directory containing your Quarkus project: - -[source,bash] ----- -./mvnw quarkus:add-extension -Dextensions="config-yaml" ----- - -Now Quarkus can read YAML configuration files. -The config directories and priorities are the same as before. - -NOTE: Quarkus will choose an `application.yaml` over an `application.properties`. -YAML files are just an alternative way to configure your application. -You should decide and keep one configuration type to avoid errors. - -==== Configuration Examples -[source,yaml] ----- -# YAML supports comments -quarkus: - datasource: - db-kind: postgresql - jdbc: - url: jdbc:postgresql://localhost:5432/some-database - username: quarkus - password: quarkus - -# REST Client configuration property -org: - acme: - restclient: - CountriesService/mp-rest/url: https://restcountries.eu/rest +[[configuring_quarkus]] +== Configuring Quarkus -# For configuration property names that use quotes, do not split the string inside the quotes. -quarkus: - log: - category: - "io.quarkus.category": - level: INFO ----- +Quarkus itself is configured via the same mechanism as your application. Quarkus reserves the `quarkus.` namespace +for its own configuration. For example to configure the HTTP server port you can set `quarkus.http.port` in +`application.properties`. All the Quarkus configuration properties are link:all-config[documented and searchable]. -[NOTE] +[IMPORTANT] ==== -Quarkus also supports using `application.yml` as the name of the YAML file. The same rules apply for this file as for `application.yaml`. +As mentioned above, properties prefixed with `quarkus.` are effectively reserved for configuring Quarkus itself and its +extensions. Therefore, the `quarkus.` prefix should **never** be used for application specific properties. ==== -=== Profile dependent configuration - -Providing profile dependent configuration with YAML is done like with properties. -Just add the `%profile` wrapped in quotation marks before defining the key-value pairs: - -[source,yaml] ----- -"%dev": - quarkus: - datasource: - db-kind: postgresql - jdbc: - url: jdbc:postgresql://localhost:5432/some-database - username: quarkus - password: quarkus ----- - -=== Configuration key conflicts - -The MicroProfile Config specification defines configuration keys as an arbitrary `.`-delimited string. -However, structured formats like YAML naively only support a subset of the possible configuration namespace. -For example, consider the two configuration properties `quarkus.http.cors` and `quarkus.http.cors.methods`. -One property is the prefix of another, so it may not be immediately evident how to specify both keys in your YAML configuration. +=== Build Time configuration -This is solved by using a `null` key (normally represented by `~`) for any YAML property which is a prefix of another one. Here's an example: +Some Quarkus configurations only take effect during build time, meaning is not possible to change them at runtime. These +configurations are still available at runtime but as read-only and have no effect in Quarkus behaviour. A change to any +of these configurations requires a rebuild of the application itself to reflect changes of such properties. -.An example YAML configuration resolving prefix-related key name conflicts -[source,yaml] ----- -quarkus: - http: - cors: - ~: true - methods: GET,PUT,POST ----- +TIP: The properties fixed at build time are marked with a lock icon (icon:lock[]) in the link:all-config[list of all configuration options]. -In general, `null` YAML keys are not included in assembly of the configuration property name, allowing them to be used to -any level for disambiguating configuration keys. +However, some extensions do define properties _overridable at runtime_. A simple example is the database URL, username +and password which is only known specifically in your target environment, so they can be set and influence the +application behaviour at runtime. -== More info on how to configure +[[additional-information]] +== Additional Information -Quarkus relies on SmallRye Config and inherits its features. +* xref:config-yaml.adoc[YAML ConfigSource Extension] +* xref:vault.adoc[HashiCorp Vault ConfigSource Extension] +* xref:consul-config.adoc[Consul ConfigSource Extension] +* xref:spring-cloud-config-client.adoc[Spring Cloud ConfigSource Extension] +* xref:config-mappings.adoc[Mapping configuration to objects] +* xref:config-extending-support.adoc[Extending configuration support] -SmallRye Config provides: +Quarkus relies on link:https://github.com/smallrye/smallrye-config/[SmallRye Config] and inherits its features: -* Additional Config Sources -* Additional Converters -* Indexed Properties -* Parent Profile +* Additional ``ConfigSource``s +* Additional ``Converter``s +* Indexed properties +* Parent profile * Interceptors for configuration value resolution -* Relocate Configuration Properties -* Fallback Configuration Properties +* Relocate configuration properties +* Fallback configuration properties * Logging -* Hide Secrets +* Hide secrets For more information, please check the link:https://smallrye.io/docs/smallrye-config/index.html[SmallRye Config documentation]. diff --git a/docs/src/main/asciidoc/config-yaml.adoc b/docs/src/main/asciidoc/config-yaml.adoc new file mode 100644 index 0000000000000..febdf4aeeb4fe --- /dev/null +++ b/docs/src/main/asciidoc/config-yaml.adoc @@ -0,0 +1,206 @@ +//// +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 +//// += YAML Configuration + +include::./attributes.adoc[] + +:toc: + +https://en.wikipedia.org/wiki/YAML[YAML] is a very popular format. Kubernetes relies heavily on the YAML format to +write the various resource descriptors. + +Quarkus offers the possibility to use YAML in addition to the standard Java Properties file. + +== Enabling YAML Configuration + +To enable YAML configuration add the `quarkus-config-yaml` extension: + +[source, bash] +---- +> ./mvnw quarkus:add-extension -Dextensions="io.quarkus:quarkus-config-yaml" # Maven +> ./gradlew addExtension --extensions="io.quarkus:quarkus-config-yaml" # Gradle +---- + +You can also just add the following dependency into your project: + +[source, xml] +---- + + io.quarkus + quarkus-config-yaml + +---- + +Remove the `src/main/resources/application.properties` and create a `src/main/resources/application.yaml` file. + +NOTE: If both are present, Quarkus prioritizes configuration properties from the YAML file first and then from the +Properties file. However, to avoid confusion, we recommend removing the Properties file. + +TIP: Supports both the `yml` or `yaml` file extensions. + +=== Example + +The following snippets provide examples of YAML configuration: + +[source,yaml] +---- +# YAML supports comments +quarkus: + datasource: + db-kind: postgresql + jdbc: + url: jdbc:postgresql://localhost:5432/some-database + +# REST Client configuration property +org: + acme: + restclient: + CountriesService/mp-rest/url: https://restcountries.eu/rest +---- + +[source,yaml] +---- +# For configuration property names that use quotes, do not split the string inside the quotes +quarkus: + log: + category: + "io.quarkus.category": + level: INFO +---- + +[source, yaml] +---- +quarkus: + datasource: + url: jdbc:postgresql://localhost:5432/quarkus_test + + hibernate-orm: + database: + generation: drop-and-create + + oidc: + enabled: true + auth-server-url: http://localhost:8180/auth/realms/quarkus + client-id: app + + +app: + frontend: + oidc-realm: quarkus + oidc-app: app + oidc-server: http://localhost:8180/auth + +# With profiles +"%test": + quarkus: + oidc: + enabled: false + security: + users: + file: + enabled: true + realm-name: quarkus + plain-text: true +---- + +== Profiles + +As you can see in the previous snippet, you can use xref:config-reference.adoc#profiles[profiles] in YAML. The profile +key requires double quotes: `"%test"`. This is because YAML does not support keys starting with `%`. + +Everything under the `"%test"` key is only enabled when the `test` profile is active. For example, in the previous +snippet it disables OIDC (`quarkus.oidc.enabled: false`), whereas without the `test` profile, it would be enabled. + +As for the Java Properties format, you can define your own profile: + +[source, yaml] +---- +quarkus: + http: + port: 8081 + +"%staging": + quarkus: + http: + port: 8082 +---- + +If you enable the `staging` profile, the HTTP port will be 8082, whereas it would be 8081 otherwise. + +The YAML configuration also support profile aware files. In this case, properties for a specific profile may reside in +an `application-{profile}.yaml` named file. The previous example may be expressed as: + +.application.yaml +[source, yaml] +---- +quarkus: + http: + port: 8081 +---- + +.application-staging.yaml +[source, yaml] +---- +quarkus: + http: + port: 8082 +---- + +== Expressions + +The YAML format also supports xref:config-reference.adoc#expressions[expressions], using the same format as Java +Properties: + +[source, yaml] +---- +mach: 3 +x: + factor: 2.23694 + +display: + mach: ${mach} + unit: + name: "mph" + factor: ${x.factor} +---- + +Note that you can reference nested properties using the `.` (dot) separator as in `{x.factor}`. + +== External application.yaml file + +The `application.yaml` file may also be placed in `config/application.yaml` to specialize the runtime configuration. The +file has to be present in the root of the working directoryrelative to the Quarkus application runner: + +[source, text] +---- +. +├── config +│ └── application.yaml +├── my-app-runner +---- + +The values from this file override any values from the regular `application.yaml` file if exists. + +== Configuration key conflicts + +The MicroProfile Config specification defines configuration keys as an arbitrary `.`-delimited string. However, +structured formats like YAML only support a subset of the possible configuration namespace. For example, consider the +two configuration properties `quarkus.http.cors` and `quarkus.http.cors.methods`. One property is the prefix of another, +so it may not be immediately evident how to specify both keys in your YAML configuration. + +This is solved by using a `null` key (represented by `~`) for any YAML property which is a prefix of another one: + +[source,yaml] +---- +quarkus: + http: + cors: + ~: true + methods: GET,PUT,POST +---- + +YAML `null` keys are not included in the assembly of the configuration property name, allowing them to be used +in any level for disambiguating configuration keys. diff --git a/docs/src/main/asciidoc/config.adoc b/docs/src/main/asciidoc/config.adoc index f7045d627df0b..e0fb0a9292b56 100644 --- a/docs/src/main/asciidoc/config.adoc +++ b/docs/src/main/asciidoc/config.adoc @@ -7,10 +7,13 @@ https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc include::./attributes.adoc[] +IMPORTANT: The content of this guide and been revised and split into additional topics. Please check the +<> section. + :toc: Hardcoded values in your code are a _no go_ (even if we all did it at some point ;-)). -In this guide, we learn how to configure your application. +In this guide, we will learn how to configure a Quarkus application. == Prerequisites @@ -30,7 +33,7 @@ Clone the Git repository: `git clone {quickstarts-clone-url}`, or download an {q The solution is located in the `config-quickstart` {quickstarts-tree-url}/config-quickstart[directory]. -== Creating the Maven project +== Create the Maven project First, we need a new project. Create a new project with the following command: @@ -58,10 +61,11 @@ It generates: A Quarkus application uses the https://github.com/smallrye/smallrye-config[SmallRye Config] API to provide all mechanisms related with configuration. -By default, Quarkus reads configuration properties from <>. +By default, Quarkus reads configuration properties from <>. For the purpose of this guide, we will use an application configuration file located in `src/main/resources/application.properties`. Edit the file with the following content: +.application.properties [source,properties] ---- # Your configuration properties @@ -69,21 +73,20 @@ greeting.message = hello greeting.name = quarkus ---- -== Injecting configuration properties +== Inject the configuration -Quarkus uses https://microprofile.io/project/eclipse/microprofile-config[MicroProfile Config] annotations to inject the configuration properties in the application. +Quarkus uses https://microprofile.io/project/eclipse/microprofile-config[MicroProfile Config] annotations to inject the +configuration properties in the application. [source,java] ---- @ConfigProperty(name = "greeting.message") <1> String message; ---- -<1> You can use `@Inject @ConfigProperty` or just `@ConfigProperty`. -The `@Inject` annotation is not necessary for members annotated with `@ConfigProperty`. -This behavior differs from https://microprofile.io/project/eclipse/microprofile-config[MicroProfile Config]. +<1> You can use `@Inject @ConfigProperty` or just `@ConfigProperty`. The `@Inject` annotation is not necessary for +members annotated with `@ConfigProperty`. NOTE: If the application attempts to inject a configuration property that is not set, an error is thrown. -So you can quickly know when your configuration is complete. Edit the `org.acme.config.GreetingResource`, and introduce the following configuration properties: @@ -121,8 +124,8 @@ $ curl http://localhost:8080/greeting hello quarkus! ---- -TIP: As an alternative to injecting multiple related configuration values, you can also use the `@io.quarkus.arc.config.ConfigProperties` annotation to group these properties together. -See the <> for more information. +TIP: Use `@io.smallrye.config.ConfigMapping` annotation to group multiple configurations in a single interface. Please, +check the https://smallrye.io/docs/smallrye-config/main/mapping/mapping.html[Config Mappings] documentation. == Update the test @@ -167,10 +170,8 @@ You can also generate the native executable with `./mvnw clean package -Pnative` == Programmatically access the configuration -You can also access the configuration programmatically. -It can be handy to achieve dynamic lookup, or retrieve configured values from classes that are neither CDI beans or JAX-RS resources. - -You can access the configuration programmatically using `org.eclipse.microprofile.config.ConfigProvider.getConfig()` such as in: +The `org.eclipse.microprofile.config.ConfigProvider.getConfig()` API allows to access the Config API programmatically. +This API is mostly useful in situations where CDI injection is not available. [source,java] ---- @@ -178,23 +179,6 @@ String databaseName = ConfigProvider.getConfig().getValue("database.name", Strin Optional maybeDatabaseName = ConfigProvider.getConfig().getOptionalValue("database.name", String.class); ---- -== Configuration Profiles - -Quarkus supports the notion of configuration profiles. -These allow you to have multiple configuration values in the same file and select between them via a profile name. - -The syntax for this is `%{profile}.config.key=value`. For example if I have the following: - -[source,properties] ----- -quarkus.http.port=9090 -%dev.quarkus.http.port=8181 ----- - -Then the Quarkus HTTP port will be 9090, unless the `dev` profile is active, in which case it will be 8181. - -See the <> for more information about configuration profiles. - == Configuring Quarkus Quarkus itself is configured via the same mechanism as your application. Quarkus reserves the `quarkus.` namespace @@ -203,24 +187,44 @@ for its own configuration. For example to configure the HTTP server port you can [IMPORTANT] ==== -As mentioned above, properties prefixed with `quarkus.` are effectively reserved for configuring Quarkus itself and -therefore `quarkus.` should **never** be used as prefix for application specific properties. - -In the previous examples using `quarkus.message` instead of `greeting.message` would result in unexpected behavior. +As mentioned above, properties prefixed with `quarkus.` are effectively reserved for configuring Quarkus itself and its +extensions. Therefore, the `quarkus.` prefix should **never** be used for application specific properties. ==== -Quarkus does much of its configuration and bootstrap at build time and some configuration properties are read and used during the build. -These properties are _fixed at build time_ and it's not possible to change them at runtime. -You always need to repackage your application in order to reflect changes of such properties. +=== Build Time configuration -TIP: The properties fixed at build time are marked with a lock icon (icon:lock[]) in the link:all-config[list of all configuration options]. - -However, some extensions do define properties _overridable at runtime_. -A canonical example is the database URL, username and password which is only known specifically in your target environment. +Some Quarkus configurations only take effect during build time, meaning is not possible to change them at runtime. These +configurations are still available at runtime but as read-only and have no effect in Quarkus behaviour. A change to any +of these configurations requires a rebuild of the application itself to reflect changes of such properties. -1. System properties -2. Environment variables -3. An environment file named `.env` placed in the current working directory -4. A configuration file placed in `$PWD/config/application.properties` +TIP: The properties fixed at build time are marked with a lock icon (icon:lock[]) in the link:all-config[list of all configuration options]. -See the <> for more information. +However, some extensions do define properties _overridable at runtime_. A simple example is the database URL, username +and password which is only known specifically in your target environment, so they can be set and influence the +application behaviour at runtime. + +[[additional-information]] +== Additional Information + +* xref:config-reference.adoc[Configuration Reference Guide] +* xref:config-yaml.adoc[YAML ConfigSource Extension] +* xref:vault.adoc[HashiCorp Vault ConfigSource Extension] +* xref:consul-config.adoc[Consul ConfigSource Extension] +* xref:spring-cloud-config-client.adoc[Spring Cloud ConfigSource Extension] +* xref:config-mappings.adoc[Mapping configuration to objects] +* xref:config-extending-support.adoc[Extending configuration support] + +Quarkus relies on link:https://github.com/smallrye/smallrye-config/[SmallRye Config] and inherits its features: + +* Additional ``ConfigSource``s +* Additional ``Converter``s +* Indexed properties +* Parent profile +* Interceptors for configuration value resolution +* Relocate configuration properties +* Fallback configuration properties +* Logging +* Hide secrets + +For more information, please check the +link:https://smallrye.io/docs/smallrye-config/index.html[SmallRye Config documentation]. diff --git a/docs/src/main/asciidoc/images/config-sources.png b/docs/src/main/asciidoc/images/config-sources.png new file mode 100644 index 0000000000000000000000000000000000000000..d69e91eba05cfba8843261d8496b4a02fbe1116c GIT binary patch literal 35194 zcmeFY_g|CQ^EPf-SFr*LQUZvGg(@l%YF23i3Zf)|(A0?1N$3epT@Y!BpcJVB(h`aw zp_knVi5L_SLXc1v0tAS_hE5>x++pA4^L)$m7d-v|FUiTd=bo7}bImn#Vs2ZS9yus= zaM!L~N6c;*-PyHkKWNvk-M=6B75Iw?+C_8Mt|z<9jIP-P5BzL)eDAVqms77ES`=6R zz1N|@KTGM$k)R$Zu2}eUL1f;qrhil`!ml5`Dw{x6R7%YK?bBI_d|wTMVl92C}R0531#)u76;@#I*rRq|NF_V{p7IKp&%jc>j&(D{JlmG9@_O@G5qiS z5r5;PPYyT2gAzrm`kKbXD(V&~9M08Yw+%c3ItU&)89dar(u{o?r~vF0YI6FabN-0I zTmz>(6$MQ{%bPuA@eJR@{=6^}F@Bup6FPHDNdDn%|1aN23eHyk38Ut~W3DaT-=OSU zl?rNj>1EX1v+i4)bL0Hw8cKLVz#q2+!UNkzu3+D*F4_N?u;@GH=fCaY)EGKCt**M= z3gJn~M`m7Vcs_*?E$5%xR1@0uULN+l&!X|~o{dp|LX9Zll@0dWk&M;h2_tq2d@cN% z>E7#82X+fK-TV@CH#|7IkKG#_zO}^4F-{Y{{#C}&VvJK=v>l*Fh^OAQ8knnl>F|hxYQ;|5~_pGiP zKH*beB45f(JZ0$rk>+&#QNZ4>UuH~<01Y^rL2)*9dv|#*&?<~r-FI87Hh+Gw60S3q<~O=N|*J^7JVv^7?dlC#O%ws<6wrJH5wE!?j@<@(zJ8Tosw zIf=uIHLEH)>-{HF8R2aF0eRid$B?z9xHbhO_Ldd6W%kSV9y7qM_Wrj5PqafGvc^hFr2mj zqQS2}+JY5Mu4(wfAO=ng#xPa&#QP8J69;jSmTzjF!=(oBLA@NCt8?%IWCJIo62xBL z=BvsaIU}|G7k?Y4o*8-bin<=Z;AD)c&h?+v$7htJh2A(Bgsv;pI{4K4%7cXD512}9 z8Gdvb`2JFL;!;_}Bd+}1q=aQFH?j6K`4fx?k}SqRT7}&=Ax1;tin!_Gl+30vHeVJh zF!%)Rto-q=+LpEC2|VO)tLX!krVQr<>F7cEhv{X|>8YovGm)o2_ct8_&fU0JHIaE+ zNMrpNTC0m;y1k}hB=N&t76jTSAQ4^Bw{OrP*@`o^))NCiNFkqXzqd&r5x z&rn8S(d)vvCp$tv{^b6XlCeMWvq{w#bL!dvQUzG}|Gzr?Y2O<5#l@;GZ5lE_BpTkp zn4Sg+30^>mEFz4H6pmEbdBiWkCOeXjmwG`ldlmkVYaRw0EOwg)|G!uLqrU%ayR&zs z!YPmlZZiV6BmV9k1^;UWuzcsW4w(K178NX3PX`PuSh6D^@K!s2KlP8Szl_?LASel-D${#WFkzdnct3;@W#^PhkJ_)Xwm+n^ma z2pmALVn2Jab$N7R|1ejY28md3Ghq6IPVybsTOr$2t)dcHg^Yx+(YX4r#{`n?XzITr z|MwBBUlyJ-TD;d~Mz}IXqS0MfN4~B`%x`0{H$nQ7t)?3G`X*PUn=J!6mm7=)zPIzT z|25IS74ic0j*L#Cemu=pJ+?J|OT->}`7}r?V6L+&W*Qscn} z_{b_ATVxFOzPjPi@j~F;|Jd-~-`P1B0w3_5&CEpEOgLJE>TgUxw){}$Ou|ZL{+2UMwmb}tjNTj4LX+SCQ5ba0&;nm6tT{-11L9kKq zqmeP~bh2&ce~#8EkaL@3(9m+y#$4n4)!}v^YCuLm;lYBCITx940GakX0XG3o#<(Xr zku!DwfN6(FM_TJ@R>Z1J+PKF4h~>xOTmB72vJqqcQV=!FB2^CS{!IdxWS-=Wt|#zl zdpZ_9GB$(oA^iy4E5aMM$Zs>AfPkrF4 zyB)o9QF{f0r-BU(mYN!pJ+n=_;2U>t*?alug%7BC89D@V^r|VSpE_O84f-ZFfqJ@? zB5=YT1z!(T0`a$*3F;wmXKpOq;jcq-uK?V&E3V)6sl*XwTa z8prJhQ&N@|c~`8&4XttO^>x{GTXjQpo?}OGSf9p=4djojCSa4%NtZQ;!(Mc$Rb}ti z8q&auN-nGN&vP$hp z*efvNWE8S)T48bk2z((BttY@iy9Qoy_Nd3n7NTAU$K;(i7Z*Ae_v*aegMDyCP`-a0 z4R`4aEurd07j-&+JT~dhBE9dwd|#k?eTiO6E$j7! zv2sO_>Pk~WeNq=&URKwv!6Cp+=uKBi;i5-jfJ0;7JazdoG2NP7&RMfN0AtI?wa;+- zFgVdG=B`#1$fWiM#IcitB=InxoOtknAnXSoh-03Sh*QT}luH9ni5U$hv6@4$tS1J0 z|1Q4{7_UzqiN(=rzeahCHJ{`WIR7Woe6Nv(rtySfQFKS&2!2`0Jrmf`ya7$IZw*>>o1H= z2K*kROHRD`_^>G{8%XjIw1mC9YthpCfxv$X#DF|!&1}zlglRqbrY%UxfZLrXbKCE9 zUoT7oiw7o`mb@EzS(B7}<1;isRb>3L4n&S2V}I|c2r{{ibKIIb~SdGibxdfGHPng_wa$;ZnLJVnzlW9l z!dQ?2e-xtL?EwT3#{C`vzI!M`-g&Lg`xK~SE(+O%zNaXr>jSFeZYol!*93vv0goF0 z6^NzsWm&) z10U0$oJ%Dsp8H@Vy^!vj)nlviX0?E{6*?F_7ovEO=ochD+Mik{Yt{$ua{k=`ks9%>L+vcd`@HJl3ipzE`rfOWV~+6KZAUY*ReDtgb2)jy-x{L z@+7SY6-sLye!rQxe@;5nt3!3WXys3jd6SjdO4N7*a7Y(V;E+C`Zy_1~GJgH;Uq-=M zdRsMAt5zTV1&V24gN$6n$SbYZjWQ%g4!dbsM8nP=YZljtMvd#lq8#E-Ki$7*!@z+g z`vfmlVgTN&1e>zVPATWOmkfx8Abqn_2uQ@=HD?z4QwZhaG6+egCTz-f)U|TZJxljW zCF!T|g?K@dsRGc}{#uNXsaacY!OG{F@sxdR>Q-c5<>QW`R&GlVYjybCh|ZzWv~cBwjR6{6i0qiXSU?r$)1{-1ma8`K@*!mzh$GuB2(auYN~D6^;G_a5 zVkVK113SL5?~N9I%3->RpgKDkiEQw8knkP)=I@{-jC)v1<{s8M>cA2>QAz7Js+@E~ z_!XV5q0#mImoG((x(;eT_~Xbae;oMU=oF{(qyewfX_gTN`FnQ0HV3<1B=YZ<6*7&} z5h^~=rSO1cRtYK5!bY3!3TX1-j`frBZ8TdEL)@&I^p@PNs! zj4t?zaI_tU8QpZ&xBZ<<<%+H>VDS?Y?@CmO6qsA1fq3QLKnPZzK^4# zX3AM*IaL_BIMY>kUie|8f|ziRIF2KHSIWma&w?Jn6!n1ad)Mc4P3O_!PnFF1Wt$!k zJ452-uBtLe&Wc3Z#widh0J$9Ta6SMDhs*&L47qZv(nRYQS6wW{y}1)eCsaeLrpxva z#B}sY{X)pH!f%=>G`sHsMVdd3jea_E3i#Yhm$xCewK*Lg#vWO>dG&EonE=`dQ4j-JmI$0zrlWV}&?a~!a( zV@-y5M~_TOo#T3D4UY3|`LUVpY)Cm`RupH4#WwVDbaNi-%QyTl&G!K%@`4xCFIP2K>ULO!x5QJFrwReW94=;gL=*PStLZXll0WC!jYd>I; zt!ItoLWh1Y8ndzv$VNPy;SQd)>4I?QMs&Vp4F7#uJt>M{Vbb8) z{O?!U{O{OmX9EMfKV~$%h{mOiAp|~^h^fA*+L-Pn+RL_}^(`5s(lKuOY}N_tU_8~V zt9Fvn%FoR6DqEqkwR}80cy&Go;=I+X150x=2wK1rDk{Gqe%$u;#Rd(PpahBUS=Ys4 zto7X9q^sBVcjg>ZOjJp@g0DFj;SH(^?_Q=C#j2 zs>%j0GT+#DSZ!pD5#SJA3W0lKWej}iX_;ZV^u?FIe@;^$;dPT)mjd~>#qBkYl*NM@ zWV|;>#FQHcOuctq18?0r(>)d>R=X!4D*K_OtdI4jb6=0QTV+BDrD*Tnb!Vnk75vU5 z5&~T9Ke)y*OW4VEIbldJuitf`FWi`$!jRr)r+1WINuyqww@;}_NfP(vj@UhP9~o<* zwm#O7>hcTt8k#w#(`1!Gr)&Gn=Jd&QWjGn4oqek_3Fb9ezBkhIo1*~rSz3W*$w%Cx z!&Un9JOAjfd+@igfhlLhT((FQz+Z!QE!>G9wUPBchHAtTbfk7OMy_%73UBpt&Zgo! zS#shr?~pT~{9k%5JIR^H@VaJMl>F8ln%jr;q0D<>3@m9zJM994t9V4IR3zxb%|qT#2~e^b|-` zmU~CQZ*~9NACLC~O5v*_L+jEI7nP#j^k_T(Kq1qLp5)i%#fxZHnV$0= ztZ+ByY84;2L(mC#?BE{N?EP{*Dv>0J!G5l7NXUXg8&V2CWEYjs$XzU)z%ZMRahu%i zn;osUcy*6D2m!$(V>RZsup~OuCT1#36z56Y_mj%#TkF~}OhYl;jzedYHS#ic!?ce2 zlPnCnuWW>~c9GE=K}wBBtWU&Z)nE#f=#Vq3d4Kn`Hd2@!G(0kQD*BL5oGhbNY{<@m zUpLlQjJ9u9b;{W)rMv*yUo%^=2m9{*iO)e2S*5`GQ6?(HWoITrffh8D_h>seCuNOED(B@5_=Z{6Y8rA^_tK92W{Ni z4>+_DfN_uA0h`ZF-&!3SS^nPRZW3o4bA!LpXt?o5Yxvw}SWQRL@i$;+0WO*qGKGGf zo_FlFjZSVOQd~+SvzVbK7fwz%m44%hhC4pHh^MD1X6Ha?E46(igiD@6)bqzQeQ@|! zF83Y6_4YgZa$f?l*}L@J*h>y2OF)Ta4kqkPV3!FE-@4k(4ZB`ZolC+UV(xU)zBM#w(S56j%FD+$6+n##vJ@bz5_Q|^e23B09ibkOIH+E-(+ z>_Wha9sLPNDRfz)L({rE`=gI{4PrLqk*9G%N(rQ~k8uv9nRTgf;SSkm(Pqqs*)wof z06XrA;~smJAfVDUfC8f^H3aXX^wb{3%`s#cSsgELXV#R(N9TsLGEj6%U~nHA%WCF5MJAp>c>oaVO|MBWL&idW5P@`?k6ybX9$uH2~AB%-U_x)uPmET6p_9<{L0jdL90E-O7 z&O#>j^96yi%BLPZfi{kpOYbkAraY~$wJ-sDpA+{p{3UZ+&YR!Q3M7Ub9Hh>e#+U~l z6~h^(W~H+DP!H%=2$@?7C^3Zn!t0>q<>9(`IVT z-Rr-9+mIJ2o__7_(55!ppX8E^@+94oISnE?rk5u>EMKsj3M8o}A`;qv1UVF)0yW}( z7i}jnw|PyJab(~pGFKR=2mWDy>sD-Q%(jk{{ry4W^(F^VsC-)W6zS*}h4u5Jk9SW` zpW!umsv7oOaPofrJl(RZow`tmw?2&x$#>{vibYLbrIzX$jRv~{PIm$)iZP6G6pv4S zq8Il!5mAVfyz2`mS4w@X5-1=Q1NErGKkY1$_vOukxPi4-YSw zx~xH^RVXRiBaLukIP2_5_m8>cZl<;k7%NE!rx-@EzRi3~0s9BI46<94zL<*#dU*tt z>Wd>uN98{DSCPcji$rS-k?XEP%z=4Baok2IP^0d!gjCYGnw!a}S8aDE9x#FvM1LAt-cpeIBy>iPNRHNjON6F#F`NyWV1S3OP(TN?)P$y+1(xlFyd}s-W#2zlzN3 zK-^pvYLS&DFh09}6nzzGJb{Boy=7+L z#H{N@yO1Za+Vr$U;1r?bKkBLFMfQG6AwV^q88uiCO-rYP89k+G+&@fO*Fb4sl zbLEWeauEC`A!#ARX{+j_P>bV1Q?I+AA`Ms&g6s}ak?A@OQbaGOt;mdmL5};MJ7_I! zX4;pZ257g98+GV=+N%Q4$Mh?^7XC6?S0Mdc%H7u8 z5ADg77NUr);yayr#TMW|Az8RIwnc4s&CyW_>T(=2kE*)QZ<(nRneXB-ykamqHOsil z){t2C(Jx;QYii0ie^>vxJGqc+>pH^HU{o#EPZNH|Q(cQu@oa#VB(yA558yX>-!=zM z`VbjJ%tEzj+VK2L=qb?ZB0w4l`a>c(={Um1nGs*6^*Q*aor<|RY}O|K(+8vKPp{s2 zl2p8esQuzldaQQ1!Dr)&%P_4;!dHjf9|(v5R0FUqSG!B%1&$!i54CuaAcji{6i*Wm z6i?U+0*#OD-h}Jeg zo0!w6ov=0MCXDN;N8kHv4SZ4<7oAb7xAy7_p>^;yz2}i+8c|VScKmDGJf2l zCx;9in@x2|u7%WSBnRsPK0EP{7~smNjJxxV^Xg_i6J$>}M_?VX4n0_&LvlK^kQdzM zCsyE_LQQvC4B=IZ;poBX2q({Nsdl&0PfOLqy%PW^c7g zdn6#iFfc;L9bk4^=6tYcf~En=hK!wI9{@rGOt zdG=MxujEP@v$kOV2hZLS=Vji0AIqZFoMHWNmUbj-$s2V0&~ghGy|e|h2#jRiH>QV& zM_A|}DD70m)vDiKM*?p%c>N*{UuQO2+{9~%@b}9!fxA+?VmK>XHdU`rfr?OjU+9{G zl2DycZ|zEg_Y0JNTxS!gLk_+YK$3ARLiL8*=@>tCsTbRqVob*XrJEg5)qSM$)v0*V zi-l4rFPpbD;T=_dh<>k#N=VK7;rce@x_Pk6behW}`ZKKxW)GWS**uA$mXUl8Q2EU` zZ$t2mAI^JM4_k6XrLa|5ia3CTZB$+eJ^PJq92QPv)~o+u@O9?7FObDn6U)V`@iqAk zb|OFo&-8krdC&Wnd(0Gd2zSK_NV!UiKxFP&6*AQ?cSFSN`CtV$&)bQCMARVTh5-du z;MYG~;-dh0J8L>|f{eDc`4Y?+;fEA$r*8jstQouBHNst6Ksxg$-8A!m$=^yqWlkjQ zZDz5iC{G=C(&%dR?ufqBCO=NE?NEPu-}efs5o^dr&pTjuL@j!GWz7nXbl=$AYY5l1 zeTEubIC6?n7`pe98U^+G@1&{3UEgz{jd$UDC^PjbZLcMg9)9kbLF0eGzYr%HA6$%6 zguuNTWh=&$vOnDREVJsdp{*iS-Nb6?$pK}{@!Ej~#|#lq-LW!{;qEJ0NS~swAB820 zyt=E0=gL{Vwar}cav8G+C<%GdDj}bi0PQy6yb)lEbp6=lg24wZ^Uo{1Omh@jfyX4Z zLM{JMsswiLm|DwXCwF5PnfqH*{x5G4IW+?rI_|$CplarG?Noi-gOLS?<*BR1)|<p62vV3&344Qp z0|OEDwZ3BBKRq`>;1{>Nd)(dM@FC4@Ybs)elEFiz?5_r zn(3%&9V%B_&zp))k3r*iT7tWn6!g~xT=WH!}VOQhahbp$Gb9BR;B5Gti8(1i~}7ZflHP26SxUK-c^45jx| z`nSUWbTX#=BlF*787!`SNNCI7n(YGf8t)|34@tE$kxDaG{KkL}Z)D*vIgH%HGQ``= zlgttV0Gg(~Ps|mLMzE!SG?gWlraLq54E-#e2o6`Z+Fs%19q3&|Jg-qcy7%Jbn#XY6 z;CWE9w^dKT@tj&?W(l9h)TtRNPbrv~>gv;urJ8YT+@%R$&z3EYFWazBx2}Y4A{M%! z(O4(iPn}1Gee;aKWhd?yoNC9+W&7)eZV^~hUN2PRn{OF9-xc8b;)nOoYn=Zv`PtaC zhcr+{!EE&9x|^Hbti4-yrXc6li+DO-R^bwkJ>^E2_;yFE@L#>S=0uIVC!K5|?kT~tO>|@L{umMl< zdl!~MLrW{5%4Bqq*3r^og=Vdzo-+ubF=j~67*e7`dZ(g)!A}&kCkJW{jUH%h0y+sh zy(2*5NZCeiDH3d+J)W|Ldx%I;=3a(cw)`Oa#Q&}L9O)S*SF~tw;|yt%adkra^8*gw zJwx%C!*XBkh#|gpU;4J{ZdjQvK6*IFQnZw zbV}gpmxz9OUhXpLx8!Q;In8&Dbic*u_l1b*r$!aFhE&%?93K-I4gQ1NE%q!4V?9hF z2oY_CYu>#x&Zge?KO+mBuob%I6;}vR|{bu7Q>0(71a_wovs$E&bPazUO9%IztSu>?*T8FU95{9Hh}L&3v9rix^j0gudW88pfP%)_~f)sknI=ORoI^X#YjpZFqu-q*$${ zngzR;s%Tzeey64(Y#goMxT0#|0LN0gzN3en!Z$;+l;O$dYXL&0fM(lSA(ROdH#U`& zHQZ$zKnTNeJeuK3qY|s#8z-IFc7#df7~`?toMD$7KswhYw;iMsCft*Adyd$x%FB2} zvO<*s+zSL1VMfBMTQJL61UL|S%KR+v!xKfv6A_}%!^Gm!E9fx#tc{|gmMW-G=>n_D zzRXz!*VBZ4Tk)mA2k4L|d6}EmCN1FgKqm$DbtZqO_a~rNSQYt9sgD|QE%Iay*eaBc ztQTu8EP41Qb^fa;l5kns8rJcqZq7mfq|cSOMPrQE1Uw}KZI_Zeu&RMPUPD23l40B$ z6M69oyYh#O1!(gS% zuOC}sgSUSGPx{7IQiI683U*>`lwwr{XjeCmD9*MKd4Y7# zm9khnt;6f9M^0tTfPh}!FQcCV{5J#qKa(|TD5WW0m1At=A=+YfvD|6U2cy_7D9vB- z-ia6J&X$z(o%HZ9q$5xmI+B&V;TDA}WsiT><RXCUhaLey;zaJ zhsX&6hlt70uBxAnyB`(@1KmL&>*?rh>FBtOO4!F?2iqj#^3OlXv+WKgfM1=FR*>6> zL_!^>*a(&pcX1 zay0E`of+tr(6CugfG*yUwEq*fp=|<&RdCEttuz}5_)oJo7Dz|*_KN93$y)!?G zH8gpVQ4d)Sl(Xrvs9uR^QU5X?Cb6mbMG7&OazoULyoG=x=h<0euTN&v;SZyGp^$t<#v)vGh z6#tDQj!VAxc|(%%BUN72W6?I&37&)URMn;R7}QU?_f!ICCE%06Ou*S|h*>r!3Yl}e z?5mG6>7tub24%#AKME?&fZ>gC`&7unA7QlGCeD$^P890acx8{vc|$gL zDgET=0gkv>!`ae@<6aq?O_j46AisSqyLRW4u=+dS@E-cfPX^zi;#oIfNU*mKP@3n; z*+1XBnD6#=z*20-a06QIN2bqyXt3sxF%SiyIJ0Wns7;w)iwaVS*#4N4^X~2X+D5kC zkb&1@2C^}>2Kkwazsb=G?Rdxq^@PMx)}=Qz}&;vYbPlFT**1C*E1{JmN`(_l;C zIRl^T7;F*T$i`~x>eBXB$-&EJr@clzBBn@L_*tc`pJ#+(`!l=?eY5NOEI9(Fo-)4@ zQxf21NS zk#g@|53TvfrGM*Hpg_9McN&bq#3EklRN+|=^ap$Uc6KmtwzyF+z;OTpij^QSb>}DZ-oFa&9m)59mAU9wZlp&9rfBqYm?h@dy@6_$ z--~616S6#Ik)osE5xGZKtz()h$kxuUhi1+XXAvWER->Z>_-O^>>Prt1Z+Muo#qT`t zUPPGFbhEWb7InRp%)L9my)?Z&n}oYtev{^Fot(g1RqzRY=)vUXQX&2gmNFmK>ST$s z=Ne<2rSIxnId~KW$YfQa;*;;uAMX$Q6{-T={825H`i<5F4d964DhZ{8J=No}P%QHV zZapm?$gzEdXFaoqP=MU?RAmw-+RS@{4%e0-UgsYXr6AQbSbl8=5 zF2**W2eIm33X_UyV;Ep~p~BS1)H9XC$TKc3d{x}bBl3GabmH#lS1gCv(K%=4^1I4J z@z4_l!9)x&*`irqD+y&+CAxmq*Uq@4T+lRZTxXbk^eB^>RLHsQMAz!koIQN^=+6 z0^)~ETTSLSo^E^%$bK&C=fm#zYa<0B7~Lg@OvAp$C;MpEKU1X@rpeP2fcU`k92@|U zEnE^{8r(C+0)riqQTf!|>i4t`)`>vHgZ&a-7M}ZO!s4kVhzO@3kky9(1B6&k7}c(V z+Nbe}{+#YFK3;k0vMf8;b2E5Zr+dp}bf8xCe=~&59Irezd#mX5eOrC?KU0fh@Dn%8 zA8E7A&4oUKof#51>*tfUFc`U;M(eo#K@>Nj-qGV8?iC~+Bl^l))Be_oB3cCZs($({ z+@^Q|W1sgxiHyEEXb>>+p+rMk1ed|T|LA1$r|2_)lSbGTCZPw=%0=~A=M2=3Y#S6v zUy2?qE|As>;!3*3qn1dj2aWlTrx$d$zXlC2NIH{m%_@EHkD~H z`jRGq0Ov@Otj!fAB-x}x=8IPJz5NEM5?+Rk{wD*tCQlzf@jB~AGihz>{x?abxuTtm zHzF~imZsZZpLKRkORR6Uvu0SYR}GnIwKNXH&yX>{zEC}kS5XR^TP_+yF2^0)et^ji zb!zx}S2M>cdR=dNgzf=j8dNu{GX~roO##rU2wPfLjX3)a8LK?!up8E))gjiQ7S{6e zVxnt|SUfc3?yZWN6z^^IL`|C)q#EOmw^Tw(nO!Hwo^+%)h0b#kZtKS(f%6Mf z3|S*!`m!=k9P;V}&IiMgw%k@|S+jC7s5|(5@kY%w27Ut3;v(-lI>jcbL66l$B2T2J zThicphvP4)A2g*Iz@<(8lr(l#1UYuN)f3of%t+1jOM1=O41dv=XkGw5C<{*^U;#(G>Fc)+|kVfNR6EoFF%IqjmhrA?^&lc)tW6Pl#F#kZm*fDSG02W zpUZ)42fvIM{M&zvOVFt;TMo%q6Pl7k>zz&7a`N&qSPjq04&@#4(6w@`SlwjVjfBgC z7(w|d&(o%W^9{+H9|O)eFyB=~NO_%fo);p1&w7`!QM?&Y+9<7zt^eJG2xK&{ zxUmtn_u`m;A)zsh@?}$zGOB$=ZeRV29;%;QEsH%?{IBg74sW2QfQ<7L_4+1p&Ybr&Vy&u&JuH}cXkDi} zLu^Oa5?A?4we}x|z~X}bL5<^X4e03kr;{GWbZl?cw`aHWx~{9jk02~3`-n~^baFKS zb|X7!F|=5*H`ZYD1!Kt){)eg8=K+2_7(`epck&^{>ounoOl!{C5J1QH`>REQUOEjF z6bokiSwAAu-k2*c0P`_M7I0b~Oga-r%mG@RpoLH5{ie6o%SwFPgD4bdDcqU#(V+qKSDd1u9i zmX6iq*}T=9wQmDmcg16{jx`AM5wGOuC{R#-A3^sfW3}Y?t$eql1xdGJlz#!tLc--w zG3Dd-&o01zHE*$PYa_IukInlfKG{Frrxdk>tk2W%&abuVg749UxlMlV>_d0pJut&Q z9mRE_sy$up6I5hgY~%S~n)MBprmA+~m{Q7WtOizqQICzUdXD|A;}aRRTC|VBvSU1? z%ez%aru3>k=kFFO!|HY9z;jspqY+H(B~3WpJzYgaGtA?M&eh?^k*p>`+whs-E=eTI zbu=x1x@CEpx{6RkR8gqaT_bA?x~q2@PJ@b^1qQP8>j|s)j-7sl9e%d__Weo=0et*;2ECV7cc+yJonWF*y#!j zFyfCJXU(pfRoys>&>>M|Vy>I@7-<|YNNlY$tuI<`qvi`{niNA+IMrq4HjBQ?wy%-l zgB%97dUn`~c2-r(`}Y;&?UgE}L^0#E)EsJfOb^v-Nuzg>TlbjTcMiltf8yZiF;2Bz zskq#Nw=4Qzi>QnBGf5wuB2v21eCwOo*5vbhSRP;5!?d12kAZE@w0agt4} zd^IAC!2%_oo*eIHwbaM0nN06qoj6n}rC~8R1ge>3Z1q~n`l5^5t0<@aJ>e&Jt2Z? zCR-J)oj7BD`opMbmOkaL_#fN|)dI^qM9de0TfiMls- z2&B#EH}&w-6^3B*a$7wpYskj=Eq^<4GS2rb3_o3O4t|7@R337e0Na3h8fD6`bYr)( zPuVV5h~LCpMVsq(+EZiHZ71_;kkE@1h0zNDao_*iG zV5$wF`Xi66_()}DQ0Gz{+2BvH3H#Kg&rC6w@3%+6g=H>`@R}N*;!iWjBOOI+MC~f2 z{Nhoi?uRsglrQ}av z*>;8mxvVF5wa)rujk~5R-I;o243Si8k|}g4v&Lf4?T7iGsTG?ayYWV`pw@m7zL8V3 zTGia?2uqM9pfd07YkM7){~+8P-O=D%b=AG_>FFmhUzz-f!#x7#!px(f|5erhXJ z?yg@iHhFv0wO(?cwP%zhaj4;r*P=wC82&D)<$NarU{0F;C}+`=p3sjeBsT%YN|~G; zB00p7P4M6kTXod;p_ehVJvy?j?%BEQlKDDb!0nC&6%r%S@C1&Bt8TC+avtH2hq2Rn z2?ziv8smtyRcGQ^E6@_cpwgcwqVA-4l!@m$)hhN0h^c(SYmR6{Stb;W=!8*g6onfJ zmx)NQ5g2y5G$~89q(8`;I6G$_A^t6l{Z?v!wPrZGfAKZ-iKn70vENsVvcMINVhvUR zLG99V{QA++jBi)?X&U{&y|mF_U=&t^ee4%+Ri(p zUs(8-nGL5a%>)%c`@8(cbXYgbZnE7gzU+a$mrElB)vJM?c#OlDif3~rmSqkJs0lw2 zoVd5BOJ#ep(&~f8Z~fRS5C-82&=t?G>x3o_w5S0=vjymYVoR0FDlbBZre=wVUf^ES zStZ$Yjvy}j7LzqLFZx|tm8;Xb02ulq@yB1H@<7x|T5g&BXUjTYjo_Jm@ zn{dhJXZT7?Y5#&>aowzF2z~3A2rfCEla!TQJgZYnZ$k6y?|ewAuRmR7&RJU#;%Kl- z5I)N~FPOx2|CVYi!-&Z1;P8!&UV?5XJ-h36D%(H5&lafT%T(Uv2`9OhD793rA!<>b zdpt`~o*k8h@8tv(5s{4(v4e`;R}2Zd03vmTZO}Cz-S?*H+JGO8N;>v1=vFq0p|0(rH-DSrR!9KeC!oLL*bfM z>UL5E$P@Y2fv}$W2l1Z_g>ilrPtqCyMn!XGURGJ-P^;}w8Z{su`V6R8D)Tg~A{aCJ zBceFbJWRIvoyl2$`yVOQpyP6l0V;<^>qdgc6hIyFz~u`_XJ@l0Mh4&_H{%mSr;nqP z@5Op4t6~W$d5&dq0FS8FUGtR>QmR61Fcj}^yqlE(4E)~R&XF^xTUf5N+ydL^BW>wT zBH_%#@DiUo+Lu9#i^JMFdE8`}rVSQ<=owGol{LofHfp;c9gIdrDWs?mE z0#4>*cXDFcN)CO?BfBXl7`hYS=`sUwW+ND> zo)kt!kvz-u>pG$lFNjb(moD`_pkCiwx?%KLDcb_|P04CC^eo9g1- zLjnwZiQfZ&nZ=LFKT4=$EM8+xf#&ROv`($ZY>V^19lsI|bj|A*)L?(L$F}wJE+3@o zwcPjo6OmvovG0K*NO}6rzC2*KGYiM8cbBU|l}-YPKI|r}rWa#PQh4%u~M~=1mran3?io6 z_DylC2UcWVon^omHz zvn?^QRJ13c7oOurUC}^Z4W*4=655ySQl%n-Po@Qbfl)+;K zC!jO<>2W=5mgs~}4yx42j~-6>+!mZ2THXXY^fOq+x3Ry)D?J0H_YSx?_RkIJm4nps zVof*Ci1a9=#jsiDa)QtsAVuxzWT{i8NnWzi8kAWWYoX!Yh{UJ_vjoPec^Oa78kX%k zC(;l{poAUAZ8+`L*gslqbPW#WO}ITcGylNj&V&kCLtO!;Y5u@ux_CVw761KP_sV2g zNhH!~C2qjKz@4JvN@P7n4W<=;OKprUykeP!RH{_v84(9MVPe@C!nou!)vgI$0cFh7 zWjckxyD!68)-WWL=U~GmGM>odsiDOvkYBbE;L1z9^g(TxZ+qy8Gam)##5R0UKurimd zLF;Uiu|7djGP?E3zLYmIpe9!Y#_w~m=x=A)&N`P%=mD@=Nr+W#J#1p9SM7Tlu8nP7 zY-QE!(0KWSi%VR+nGx&1mpk+i1*k5nurJIx8(3AAy$9}Ou$Bxd$FdekE5bm!2kwyO zTx-y|^wVPrW3kbMLsx4h4;K6`K+BH-9CG*B&BVh!IfTDn*>-vvMjxc6=*2H09#YI{ z@@3BXe{jqd4}Q>-Q2-$UA21r7LZ3#q7e~1f?}(1x*w^L|nSUnzjFaO2MSp^k%`pFI z?cg2#srBZ=9R_iKHi7gD*;T^53)K!nzr`59@6KpLk7L)-`L4N1_!7B*Sf*myLvVrcBrIpRJ2<_JCFFK#&~y?M-?2gw8=c;G7{)EU%#j|?CH&omG;e(oPE4saXs z>6KCdsRsEb!(OAUWz7k;O7&H@I>^?vSG{oymWz|iM)idOF5EQZDG5NUd-7d-ue!cL z>n;VwT&S=I232Y=`jU|4r+SyxxhbAWbwGP7y_NXC+WXG1rm`;FDK@Ml3Wzl6Dg*^Y zIw;Z+5b2?fh9bT9<|wGN1VTs32ny1|P(m+?Kmr6KEfGQ)4FPE)ozQZ30R0^2`|iK{ z@8(DHJm=)>vf5sI?X}+14-88Vp(J>f>XL!rE)(X`za&(3B4#>S9n`*LA=U=xOM3zq zWgZ!vf$=M}%$RhuR_T)xS}Vu7#C$%T4ktgOo8Rd;=ndDKq`bBApu$<&X))U% ze|kYc=AEM$qe_bpDTN2fOEpYRH$n0pSn);F?p8X|y_a^g*-#f_Gwmq4-4$t$o3YDX z|8?+{th(-T6$4PoX&y#?!ex6Lwc{rMALb9i*NiXzq-dVL+FxHIBVwf2R?uFL0;gLG z1yI|h$9m5x-j1MV)Q`hIvz|7O*$3f0T$#Q}#tMYNrh~>bn^E4Y9Qw1cY4cWhu{uH) zrmu(~n)_nv{o?8UemWqBji;=`Kjc&McK`eVu+|uqGt`crM#XJAt0|W3ujEP<_wR`Z<|*%N&3S4#M-9HW(uuR5I7F2rn^ zFsobIZMyTj+;Ay9U3If)a8i}x>{y?OwXg&QJoJ;d$NY3S zh!0ZNff&MkTpHq=S2LA?!U5q<1fAF(514etafn=TUyXN{ze7azZ|a|B4LBhagA7Y2^d6OayJ7#P%4dLTx>XjaNEwp-QO z%(R~0&UQ2C&$78w^a%F=-?^~F7*ue!qNSI7!>piftJ^0aO;gGt)%~cd_MDBMVns3N ztMvTuIqJoglkdKs1+#k|%(p&}4XTuLdD+#rFW=x7+l?$dt!d!7e!l$S?TPJr zl)r>-KcwX&o-}5(GIcgC&)4{*VxFS>=KWfgmidN4IN#uLS1tDOXX^^0UQg>sLv$98 z4G8%5x=oz$9e>%lc%JGPxOSjKC=*X``}uRxNyH7}%1N;2E(I}&N{zqJZSC0UMW2^F zm*CE4_^lHjGl%N^K5iXB6kN^bTMj`(i#5fJNR!TJC$Cz#isMiR*d5UGL>Zd9v+sKM z{_Gpe!`_YyBgbl5)BZE{X%$7k5|_T(wixIl*e5*hcy|~hII?Ay*PCUtDchrX;29pn zjiS8^=LIe{IhW@S6XrnGH5|;xnCZTMkq0f6l9U&x+}RtLQ5qa1aoi`}lEjv`YNycERx+?2=tS zU{8o2QfmY#2<@Lic0C(0QLxtmneyF#6LCMQ|=&De9~ zBGFTe^)HeXdTSU<7$4}}Q}xfM3RAP?qOwjla6ua@H9FDk(WEiTCtc&kn!)bQ$Wg(i zq1vhoTzP(*1`KHk$DzklvbWO}J9LXlA4OdPi>jkZClRKF>+~v_^ai(d&9_i{4Nzg6 ze}5;aYoaHbSQ<;uz>(U1%sS%V%K~3#oaN$wH1eW&lFaeSTE1KQ3stIR8B}sTqn!A3 zJO^*gQlkg-Xcr2=y{fdj?C;2kM1<+BN^1lD%DdsP%tposma5*r-YM!>1l~sH#ELOUAwb#rvLQTmgr@p{R+W`1*nJ#^Zuis>mNE+F8T_WNu=*Z0A+OUoLaS zmuAQZp@wQk70On7$8`{-PqUO98JXT zBxtcQ!fyb>xC(LU1E3G|43$W?bf3CS&8voYMGz<7YZloq!CWi``^6Nu>n@porc~w! zH|sH_Tim!}A_X51n1f|q!!_$QmpF2@srNOuXm$oEc;AfOffo1=3Dmal=dM;kc~8_l zTzZGG2Nv-H*j*=LH!p+ZmoQ*|3&=-yD8OyUvQx3=$(mKi2;Z)1NeMF-DqX&3?EQPP zTf*iPR4pm6c&afeJ&GwBB&v*Ftx24@_2JXx2H&T5!5-87D6rS7I93|$l6+2p9>h*t z>?+w_UtqHenOHEh3T0=N;{D2&DB`Sy@_qnZqARsBbftwZ_Da|T;W;6Eb2S5G#yy5q zmZ0esg!)YI#G}y=$@1u4&*?LQJ;m1=;8KkrZheq2_-yFmqOR5de%xE1WPp~FcMK={ zw`mc5{AiDj%yt>!@!MDUisM^NU6LH?2AAnh{7o|{BgLLu5z%xSlr)Q;(0CSF=(uk* zZzsRzvBl16l!sJ^v#l{uXU>Y3NxZe5mUxGrMZKbj@_D8GzD_z2b+XF+-~}*i&!cKvif?yk{Wgp|{Q3Bs z7$}_tsbM=N&6>ykUX5*P;tTTx+xdCnN;!c)2R+*+?y?c8k8ceZ%fVWo3kfYQf#CT8 zcw%5_c_%!Q{oB$K^zjQ*RK0A}P*nfZ zK^NyxC;qhX9GilPZUt1})4OJdSx1WV3a%E7Bg9M=r_VUDHIxJh8|k(=7#3@F_Q)mf zqYDx5ouhj;5}-7dCGX%e#SSy5Nj-F1S|v?ml9TaV!%ackYo96YiLyz$@|(!gtT@0! zoD~2#a(9S;Nys2|irx1co@7xmxoK#@VivAyPwcPM?^P{LRT=UhOb*~Gps2B)4JTi% z%r6j*QF8mV*)K{E^B@foL|iJZ|)#(~S;q7c%d#DScjrBG)Z7%3rUE2nTUSs7# zbb{_oWbZ2u4?u9fPDTDCT(E9kWGgvzs3o+gW9{>LsT@BF(mQ?h==JI_8w z?OPMy@UV7a)ZQUu=n~u4Xho}v7t|@_?oV14$_h@aEZQj=`W{v6dzdt`bvPMF(D*`w znX_pL?J=S|DG`9d0P=kg0JiYrI9(Waq1ps_*-NZyq*mw11&<8Oz%J>tc!drB4$9gt z?%KcLwZ;~Ee8S1yH#XKdhMi3fk7<}0?SeXixqX|)SLT4;oiwEy-Mp4#8|!G4tl+HY`$Yj-Al!nq?7ekslK>xof8Syrxq zJfZWaoqP|0b+e2>q1xN%?Z#qz3NjQ1lrV;O20-4SVT3@yA)ci{A|0;93&GVnm zj!yUzla|M{xbh%E00wS=o1yyzE?j>HW2ejGS9HGgzntW1JPwXhCVG>W*F)FNIGgU+gs-@7J2-08+mH9m1L))w zBOK2)+T~02SL=^0g-oMIYaZR=rMJnwBZE6c{*M*{MrS2g^0Om8Pt?iL8;>jG-idmB zm4qFN5z?);B)P_Ep1Y(y14s)f)ybu^y?|G6(=sC{1}sEjCBXs$-T4O~=mWPfaZ6ql zm3^yCZ6tCZuUY3@FgZ9V|ArJYRe7Rs0-$EiHDnpf?Q}L|_5r)<$2eF7U2S zxq{Y{9B1WMhdgDCZ+zEi+>q~RaB>iQWC@GlZN?H7UfXdtP_%~WSZj45sTqer1tW$kY*Rt$h3AOQB;) zj*x%!);q&+@fvUs{I=L z`eT#;_aYX6OEQI#ukNVy8mI2t-d$^YA=G!e#Ijbp{a<-B;b^el{TkYVTrZTrDrRF-?gxRP~K?K^U z)kifprSW9Ntu;GvM45fkrSX|uJ?qIlhm5K(nI_;2qMV=kP&9um8j3Rsat zYEm1BSl>LZ1l`sgXpw_CfL)5S3fZ)?;yYV&b!PS0QTLl_5ruTHO0kEZ%v(j-Zs>Ty z{a@f|vVZVIyiV3u%C#C^BcIsRmr-)k2gV{OVs73#o_Z-Xpnh}F4xXGv{W8Dcn<-_v zy%GpdR-5A^y=@9wGy}~WOEz16)C55Xz!IS00%>%R%f$nk40Ng3YDIL0IbD%#d}pEZ z`wUBADZ8#;@SKItnL76-mqXPwi4u$L*BdkrD=CK5dzOCdTAf)N?T^9Cy+8PQC4wQa zP#5e%Y^Y{)Td5S%==viHZ9AvrWBCNU@#$@qZ%~l}><#0a>+$bCa!5O05xB`tj)>J( zCGKl{H;aB>jhhZ~^+;v=b!EJPnhig|h*&?VW>tHLyAFSfw%*MWp&D`&0DO(f%B5b* zdx?;5p1{ve@EBj)mD4vu$6PpDXxl?f3a{ddl}pfl2eUe!utunDo%iQGQT+U8?&%Jd zn20~>rH%p=-%OJCtd-%d#q}&bueV;Gy^j0y&#~-6%D#(@5k!o%RY+ zjM6o3_AJ@PSD>8;xzL*%)>3|V?T&koT|@q+L}0SeKU4O1`dFnc<8=cWq_)vj+W~cd zG4S-Or50X}V~3vc?kfr-FAK3y6?6sS;)Q&_!1pQSWsaQlUG!CH;}i@l;;l_;ag0Jq zn7iX&IS9Xq52||JMvOnRj#J~}9vkX*yZ|3K)tdPy}L#Kcnn&YTm&+ zVg=`K_{7;C!oVKo{Cw!1Ff7E1Kg{WFx)4CNACo9kxt6}bC8x*Yg~F4iom%9*mZ z>SymiFeElcNp9Dl#`y4s#r|AVS?go|oQ)2jyz_C21~Ymb3kV|ZpWveR^)mg}^9GsT z=h5MMBi_1fV;17CUn#GL_{pk{38d$cmKaEo`i2))lmimLRr;d zW$B{v_4B)}`og(7ET4x5<@iY4*Q@kj@f*&=UOk zHrBxbDE{4ZwvXDn03R=e{gVbqO)V7_uKUDgOsscHjKqBRz)#{ZYTuhn;2z*Tx$|GG z;dZ4$h{gZMxh`USc>#qMW&-EN{xv=Xr_#>&x=BAgcQoed;~5_PLvwqAw=k6ElZKd6s*GckuI>1NXfMMlS6}pSZGFBZOq*!hsxoNz(NfrY zCdo5&T%L&F{BK-->#X^LHW|9f<#Jfn7zCkv^u&6YVhe&cM;qrtYoxaTQrFw3`1oKZ zxUt9reBXBjN?}FHkr*|R(NM~C$eK-++;-c+Iq6_?q#iBlUSAVGn?!Nh`HS4kzVfTa zq4R8#Dlcf6Io|3}o)v-gU90eq#sFCHC1acoS#Yk<#0cb64C^ef{U{a#xdzA?v!z37#t@@kVWgY+ z^HMIM>uZ~#K}36@{#FNe^)34kFF`st63LigL83%zl!<=uOZ}&C;ohbA*Zl@BeNmvC z$ys$}rr?43z7L-Wg{7?y=_rSWi&PV|OaJ1!XDMT%o`|N7PlS3|u3V^>;+*<-Q@Wp8 z8uWRs`RWT~SXOK1^Bm<&jFs1sJ|m{*7&n8&yPH+H_-T{p%rB!1SSO7N2brUEB2WtKZoMcx1T>j@(c#_EcJ^uoSj`xIRx$XdPVAcJQ5iV%_`R^a3`-;m5YF~WIpL`Z5 z>u9ChWx5}4DY=$12AXbCsE}j)`{Z@VJPbD>H}Hmy^)6HceGSwgTj3_?zlO&7xIy-phAfqM+#O z-cd%yoy{KiDC0cQrzSz!t;qHF{G#%N=d{_wxc2B%)c;|HWd2Ob$U}BD>oi}64^*2N zimr0n>>FLC|wX$s`TTx7go>TnB*??<4bqhTTVLe9dehTQqWEuBo4rxZuOZJ%eb4;gU7TRiDiOtv1&tS~Z2MR0#QrKg zHp%lu-B8UTt$s8q)MC~U@=IaIn`)OTw=U90Oute;>8>bim1tFDf1^*tyDs>sU(k>0 zdFx20v%v|G2b+VKNUWxEZMeP5v#G-^r~;*^SMRs4z;8@?j}b~B)KpS4^deNL?P^(6 z;-|jaN+I_DVN126_>4(5{*|tAf5w|cFX(PKbqhYT%V!~#8?(?6vG4{BH zn5Le;xER19^!gr(ZMvY24>I zEZd*IU9Rz&(2>=Ai|M=kzpx0|f0{qXqVZcLz*vppOrD8>DXB($>gWYB0RZpyYP#i? zzi9nyT?ZNkT8%P9XOhCe;vtNXJs&4!J@iVL9fB1mt~}$pefQP|lUbRF5#!|!!>Cr_ zWAcbX&BBZN_@_d;W;`C{|HUJS1!SyRF%Q#}XAn73YT|CkotoU;A5vl1V64(P>1ZcI zDdiSoEev)~%-LQVWyudN;6fz6=!fYk+j7_6`L9+Oj1d_XWvBupo_WYwb*o4861mPY zU;@H(n@8A)>Tmw0v9bU)L|T6zX7*%78}pv5JatCp`s88E`IC^~I_Tdnx>A<^a)gAl z6dMD3dD{CQ8`kxz{00ZXG7;nxTsBUrti;1zFfs5{L~9A66rQ+^f+goUM_^;dLCoz3 zN1|ie?pk8?&502Oh&Yo-N5pHtNya=8h6ZN36y|ywQg~um^KJa4p?0GwvCjp8 zfB0`5tGtkCFmPTYui&~NZ*5t(J0<(#Y5t26#r!r-4{Ozb5i?S)4KKua7KOo#Uu5sM zOIK7J7d?))G}d1q)su6eEhr#WGlS-e-G%9(nC8glQ_5*iIgMf8C zP0=qp+&9WUKQ!1^rkj1qh^x(=l_j6&b_7h-r8Bh`%}GI~#J?LBFw^z9C_d>Ej+<@3E&k^k-L^2+OahYLx#yv)cEqIh0+xxB?p<9tur)^yeP6|?UX0Z z9h>d-Ka}maXmnq^Q~Xf_wm#usEbgSV{)zF&J#aZ$zztzXJGCp}PxbP%8#?DNV@i4X z8Cf*$*ADh{$V8{Qn}rdN;a}ka18t^LK74A17pL{UWQUSx>9x zW~;xa_w%G;`{kgl-$vreJ1^ry+P_g*S5@LAhlT1ILR z%Z3d9?XLg63z|k=L*b&tG#LveLY_^S8gFPrw4AR`2wYuUsqML3c@4c3@0IXAKA~^a zkUL+q1r^z=68k_#HJ}I?3 z(GU&`3hKW1c*^FJNnNCOT$_C~!k6J4n({v^G3X}TD#@&P{s=!ac?lJkpxg^XRqNYW zCOKHz7PYa-WPTV@d5+O$zs)h_$w(@#U7qB@zDD`HjJo_Nhf<13F3Rm>LbA2D=Tt5J z=p;&(X#GMVJPk&eorMOpu4FkdUF^O$c}8e%$=7(@e#C^L4%f=BGtp4vFy>^MYSao&q$ndT5dKMZ!MNSjqhWt^O zRK$km|CjoCP~ajA3E@_S{C3O42=O%G#&xh2+vsd7Nqu9!D@{J4*a9h*d63x;h_Ixq!1F5NG~DxM?^MJ~2E)Nh(N z;in2z6?2`t1IQ+^rU}TV{99c-w`nWVreX8kEGphps{cKRu~9&VLbM>ud{l#D6OpYd zza^kzi=ZANMof`4OojWcmreRJ`=?F9n4fWOxSxd9T@0{f?8Q&wiw)+w)Rk+si{XX% zNh2tM9$opDT8HNpPQ>Y#X6rG&>wm=jfH5d4Td9mOE-LW~?zWhMZF{QFBC`sUjSJh^ z*5^=^!&BiaXf6P3^ymkR4c?jbM?s{gN_xvk_PzGW(lg6JjyJKJDSYJYd*mq_n|x4T zOyekAuD}(PiK&sVJIEAkEjp%_E(=M|t;JxH{r?$+IU18%Wgo{UEvS)fW62zs6j9n* zz&FaHu3>zB+?}%O7?)9p{3tHHlEyQb2URcfd~p-1s8%W0N+NPyUFB_lBjPN{{jjqcf24 zmL=n>wGa)of^!K*N%`Um1BP6;6DN5^8y(p?Xl9wb`ZG;rhG%9$-((-R8}-hu_FqKK ze{8GJj_yZa=kC7g8ttr^O#s##y9u9i`AmavHZ@0l);f|S+qo^m z{Va>=`_rckF8cbG_~25a`wvx3)C6*V_Eg-E_hq4A2^Upj% zw@EPD5Elmz{zM(UK^18hehay`zla^FdzfnNg!jgkvzCJrh|3+X{F=@mTbxT4I^bC* zng=2Ah|#Vp3XYZwh1-Xe2=n9^NF0;K&Gd!s1=fDYwbb~N4K!8sSoYr;<%7v@l)9cR zV}|E+yrpzBxtMTP7T#G5E_W-6kM(~Gt9Q**8xXK0W?t}@(owG6TYuZ$Z4TjPs#y%B z83vdmX1%PLLqzjUwB88sKT)xb7MeCqe(HwPz^-hJ4H8mfqgSKumL|nJ|G`?)$$(o) z$KDX}?3Eqb3xC0Ew@0RpxjIgHmZB;kQ`xvEk4yMFIL5zZU&-|Qm7we*%b263U!=?t zjZFx5-TOv~jAac9r{WO@^2X?4u+WiAit4HJ3X^;!N1gqI%az0hVKbc#KZCn6IV( zn(>&r!~)lk|GXO;5}ImO8F&p6F{`w@c^BbN#C6M1<=R*;Xx_*Y3v(P%!(r7N-2c_5W?Z>*B7#Q)>g z$Ka3hS^eTXcA>rv-&zIS?Pz(ZWvuxMKu*+0MW-n_MYXQgOkd#f)D+dk$#4(&8d(R= z1vRbd%uAxZa70RKthbCfC#Hh@mge7ks?e;?d2|yNj(K$u2~yn^6}S za#|eoPUY|wy|4*+9OT?6(%CHh>+}`acJPMhhG}qb9Mv3Tm}M-uTjj6cuyYBB`bGoX z+(_m1R6n321WKeC$vVDnn_c$^xrO# z$BSw zQFstKF!*#h%Y0&Q$v-2$2=pl-h#YEUoseL3QFINmIGDG0M+0NMK%x_g)k`I+ZFf{`7PZ<9@pggPBJ{rjB~4lsokT zmRzUe=FM;3P)$7(LA23GZG|NzA58Zek}V(DivnJ@y<2eegFvvoAR~Fgycil^XhL2c z{*sPa_Z4LtSltXs%}8_m){B&+ZjFGhfZn;b1lUdCw&$=d3zTKdT`^0RQ;1R>wCoe_ zqR+dL@cW`y6eYzAmE-d+mMTefV9j#|CG=x?#U&fw3?JI@6EEA2&ozXgkvB6@Encv? zB=6LrnQxqMx6QnJ(@1&z2dPOedNMOo`TE<~$0u^D&evJ1Sg-gJ>-J6#+Hkx$z6ui=X1Iyp{Ort@U{NM^7?ZD2#lJJoS8Gq2 z-TP1YxIQ)TX^+H$6@avRwDNn9@M$<=Hlx;bfM1Ab)v{^OdG|c#vI6sA3}#hl_Lfh3 zd6SN}EdjE3!*YcQ?%CTRV#*Ls_Nm%EA$jFzx;*@NF71|7M zgXO-iM)YnoQ?*^Rc5d9CFTEwDa5Zoh4ca+LXOG$L(M&WVIGmiBKTB`kU2E@JayS5L zY3MEQ5b<9DrowD*==DW|4dga&1YTRH&YFMB_Ul;IOj2AnKfm$SK3@x{>f+Gz{gk+7 zMy}@1AerKZNmr{OyOF*&jM9g-_nEV1yHwLfd43xWz2}r)_P52mrl)#;qm`jH{JrO>^TgZP+Qp8! zP#CFcZF^=|KUA_Vcy)AkM1j_zHfQMK_D)vgf#&6K91ubkB^{JS>_6qG)&2 zgK%!**usPBB4@^0ADVCG60I7kkER7i{YUK-7aB`KCJDN8!`_%6Yy3mA313CGy1Uxz z;<6GSe0I;2&Ro)Z>&h-*R4|@E?tWM_y8__+q}me57aq!$m;oqg*0Ig&A@w9^TjFO&Gyi( zzZGenmqM0KaMjFJW@uvHi1w~lf2FRznH1_X^AU_mVVXXDu%_S(jDGTAx-@oRxKRUR zQoP=L-SP@nW%%x7wR_5Wu5!O1>ba6L*1ccWmErOM%eoEYd6)dj2S+^no7NX5TsGBD z$K`ULpbpI#?NLQ>HVl^e;Y>IzAx8AWnF&xi>vy-R#7)jWR=*CEiGdDH;iX0rbdE%8 zV6x7PApwi(onn($_&PAcJmr443)tj|<)VqK%>qeUvu-2h5hR{y)*0}`2B_rhp8X72 z2XvQ)$4z)ey?_-N#(>g9jzwWiid!^T1>JBLFi^SiRJio)nf8VG9%M2cOBwEoz}|%L zNH(n4SuPxz+eCM{;?YIrtF*V7@+Vv}@aLD>&H;5A{wSSIrK#j%_;WJCdqWem_$Xqzz*J84?x6dd%X(6Tc8r$h)g&giA>0Q%mZ&;#N-R#>(TyFC;TA>H@~+GhL)(e)*EBOQmHt@5$Ot zn-B5fFuu+CDA$6N=_aASkUkJDD^x7&n18l#?`+Z3#XjjKNkMRdb0YN zIj^_&beqj>V{~KDB@9P-KrfqR@Fd&zo5vykoxg@I%(?oFHJZ`hUm5F-ZRjQX9NuN( z{ZiwoHW|v9e7eLF`U?b)dVV}7=o{5awttg80?|<*Ok%Lg@#S?ddSfSiHV$LWJI}r# z@23n(^4B~Q)H8rXyJZ|S#iB5^1>Scw7b0UO8phMC*7MsHw_Ldb0&m_3A#WpQ(>J1m z_gkAMKGCgoOCK15=nyZm@0m1%BstUdz8+CQjx6z;%m|E6)U;uan_Rw`9BF>+&fURM z9eGt9R}?x-u1*7GBk!A%9*tuxL*3h&cUgLFZPC4cil4=MO9)Eh@qktN8I9Qt_ZSu* zQ5iF&eJLY`e%fkU`)uA>yYad>uq^D#F=?665pRt2a8H@u9T7C|HG2+2OI#Q0e%%U5b$LA^USeL!r z`~g3kV2!ftG9QAV9J`dtGMP+`(Uw=;$1jA=O%cs~C=jk~!KUrROG9N6#4=Te{3k=n zfhDw!d74n~o{#r9c10ND(<7>dN%zA^6nghNpv<})GeYESlyxBOzm$#pzfu0#)VRWy zni7HZ$Tl}zZ-*CRXeq050KTQ!c% zgfhCdRt%uc&EOap{(^SONH*knhU_MfyyDJJg3ku@H+~e=#Gr?_DX{S{0YM+FD6Gse z(^LB?>&S^1b&FnT6h?;MlvqJ%$1XliHx_eHnLg5q*3qz?PjQ5nKQGcp)?|Cbf`c|i z9YqlK*wM}9cHiOE0Yv?!NGw!|6R9#bgj;z_{W{-@O26nLdk=#uuaBaHV$`$-%ACVc z88m+WoG!aS6y~b8j2N-JGG7Rq<5jfZT1SH*QG9B+hpAY?A8wry8+1p*f;cG2YI+2# zo)JCtp3fNVA~%5{G%awrQd6z!mmgVCiB{B)5Hqe}e-f7(b*+oGH9voe2W&QE!@o}4 z(XgiS1x!btV2?S^<~VO+OlHvn#s<9cO8L40YJ3T-CBZgh?!!Ie=Mb0LC5laz+UCl= zV#zsCOQ_9Wp82pml&O3@RS3!pyzxjvdTcaCPqWd_ zuWPwTLYhDI6mq!;o2E7DN9nX&{lnL48Na>b3Gm9gZ1iPXn5`-^q_RdeyW?@W-wcAu z%NMY~Mi_)^@oXzBkN|s{5+;{Bo%N(>zYSnG=jgJo24P{o#l`+4>wcTlai&U@cIpJC zV$*At`HoN^q~>^gv2KV3@$4xiI>I7YGC zd3=rxrcv$Hm3FEtHhqzV_)ZBeETBk*fZnZ4(VHl{m`QAe3wU{Hes3ID=OPK~)j)hE z-wWjNk(i2?h1-+UeMj<3s#nsoK%!{YhHul#mn>QyX;rRzdHXz9)AG9v-LZl5?6O~# z#%pWZXnL?e{eihWPw>R`N_*o9g0-}19`CgESnWbJ%3l5%sVM>HT^uX~6`$W&<~Nm5 zC=v8FbOgFOiA@6(ST3r`Mx*Sz%-=zDw8jGnSEX55ZN^mOftDjB8$x==r?)BnG%w8NedohD?)E6ob@btQw_ zl!zvH@-4bs5Yt*=+I1*2giCieNk;<^0GP6mqItZFG7c(^mH;(L9d)mZq5a4sgr}HT z2lkkJ&6hB=$yPB3m8#haJw?<2bq`9aoR>SDnyytG|Pe*zn z7QKaTyNl)D_f?DUIETJ%$M#d)Ap(x`?{gvCj@0+SKDA@bNwww-(idj|i)vdL%XBnt zb!Ig(5~8gcQsd)-Q_l!Qb}VX6)e@leuX!1)G5JnUb^?X32;~XtgC1amb*^E+OrB3>%dvFZYY=Cz;Ytsz{1 zDFH@f7vzD+<``8}0waf7P8T@!rf(8kX(H#lmR8;&apbKZt@qKWMB}Q4t3R2^ZgXNZ z5Fc(u>ro4()FFaCuFv6JHgK@Oym79qrd=|8)X0t=o#o%FwuH)ZD`z`IaW`n4NB;JL`;t?a)gS{ zdX2GCyqAmG^&ijGg{+xU8{pH-oo%p=(5IWOzRGqP7k9gYJ%?1PYO8QcZ~7a2s18WQ zm?{y(c}b3ekAP={n^-8q20XG3HYcK0FPIAQE!N2JgD`})oN*ps&V3*h%*sl(C7CX+$3YKk26Jsj%V`o$2X06Bcy703#an1`z+Z%z2zB$f{1diLh z1mI&D><)=Z|qI+rRbv^T@Q&lR7IyG2BE4wwT#8PsPDvs;`JJhReqrmEu-nI%Hd zjl->tp8Q0g9IZBJ3TO9hQ>M|LXY-TpAC+NFc=${ps^p1NR$;hR2E2%39cW~o0e8a3 z79mK)rNkKY84Hw?fz;lJ^$= zr54Wyjj#G-l^Yi0ncNxl zD9I3!%bw0ka60m)-y&4h-@0mZALS1MC{Nw>27f<_F1$&)T?XOXFv=z@@{%yYl-#fV z9M{X~z%(u~A#*}P|J)U@pB`5m>WUrI-y8l Date: Tue, 11 May 2021 16:11:49 +0200 Subject: [PATCH 0021/2077] Extension metadata: support local dependencies assembled with plugins instead of built from sources --- .../io/quarkus/maven/ExtensionDescriptorMojo.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/independent-projects/bootstrap/maven-plugin/src/main/java/io/quarkus/maven/ExtensionDescriptorMojo.java b/independent-projects/bootstrap/maven-plugin/src/main/java/io/quarkus/maven/ExtensionDescriptorMojo.java index 6fd82772a2ebc..f04e504b4d504 100644 --- a/independent-projects/bootstrap/maven-plugin/src/main/java/io/quarkus/maven/ExtensionDescriptorMojo.java +++ b/independent-projects/bootstrap/maven-plugin/src/main/java/io/quarkus/maven/ExtensionDescriptorMojo.java @@ -18,6 +18,7 @@ import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContext; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; +import io.quarkus.bootstrap.resolver.maven.workspace.LocalWorkspace; import io.quarkus.bootstrap.util.DependencyNodeUtils; import io.quarkus.maven.capabilities.CapabilityConfig; import java.io.BufferedReader; @@ -503,11 +504,21 @@ private void addExtensionDependencies(ObjectNode extObject) throws MojoExecution public boolean visitEnter(DependencyNode node) { final org.eclipse.aether.artifact.Artifact a = node.getArtifact(); if (a != null && a.getFile() != null && a.getExtension().equals("jar")) { - final Path p = a.getFile().toPath(); + Path p = a.getFile().toPath(); boolean isExtension = false; if (Files.isDirectory(p)) { isExtension = getExtensionDescriptorOrNull(p) != null; } else { + // in some cases a local dependency might not producing the classes directory + // but assembling the JAR directly using maven plugins + if (!Files.exists(p)) { + final Path workspaceJar = p.getParent().resolve(LocalWorkspace.getFileName(a)); + if (!Files.exists(workspaceJar)) { + getLog().warn("Failed to resolve " + a + ", " + p + " does not exist"); + return true; + } + p = workspaceJar; + } try (FileSystem fs = FileSystems.newFileSystem(p, (ClassLoader) null)) { isExtension = getExtensionDescriptorOrNull(fs.getPath("")) != null; } catch (IOException e) { From d3fe365f39b39683344c3b236cdb9bd81a078628 Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Fri, 7 May 2021 18:01:20 +0100 Subject: [PATCH 0022/2077] Enhance TestSecurity OIDC to support UserInfo and OidcConfigurationMetadata --- docs/src/main/asciidoc/security-jwt.adoc | 46 +++++----- ...ity-openid-connect-web-authentication.adoc | 12 +-- .../asciidoc/security-openid-connect.adoc | 84 ++++++++++++++++++- .../main/java/io/quarkus/oidc/UserInfo.java | 4 + .../OidcConfigurationMetadataProducer.java | 6 +- .../io/quarkus/oidc/runtime/OidcUtils.java | 6 +- .../it/keycloak/ProtectedResource.java | 8 +- .../it/keycloak/TestSecurityLazyAuthTest.java | 16 +++- .../it/keycloak/TestSecurityLazyAuthTest.java | 8 +- .../it/keycloak/TestSecurityLazyAuthTest.java | 8 +- .../io/quarkus/test/security/jwt/Claim.java | 13 +++ .../test/security/jwt/JwtSecurity.java | 13 +++ ...TestSecurityIdentityAugmentorProducer.java | 22 +++-- .../io/quarkus/test/security/oidc/Claim.java | 13 +++ .../test/security/oidc/ConfigMetadata.java | 13 +++ .../test/security/oidc/OidcSecurity.java | 17 ++++ ...TestSecurityIdentityAugmentorProducer.java | 56 +++++++++++-- .../quarkus/test/security/oidc/UserInfo.java | 13 +++ .../QuarkusSecurityTestExtension.java | 16 +++- .../TestSecurityIdentityAugmentor.java | 4 +- 20 files changed, 311 insertions(+), 67 deletions(-) create mode 100644 test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/Claim.java create mode 100644 test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/JwtSecurity.java create mode 100644 test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/Claim.java create mode 100644 test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/ConfigMetadata.java create mode 100644 test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/OidcSecurity.java create mode 100644 test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/UserInfo.java diff --git a/docs/src/main/asciidoc/security-jwt.adoc b/docs/src/main/asciidoc/security-jwt.adoc index dd8d8bd986ba6..b8793cfde9b88 100644 --- a/docs/src/main/asciidoc/security-jwt.adoc +++ b/docs/src/main/asciidoc/security-jwt.adoc @@ -879,16 +879,13 @@ and write a test code like this one: [source, java] ---- -package io.quarkus.it.keycloak; - import static org.hamcrest.Matchers.is; - import org.junit.jupiter.api.Test; - import io.quarkus.test.common.http.TestHTTPEndpoint; import io.quarkus.test.junit.QuarkusTest; -import io.quarkus.test.security.SecurityAttribute; import io.quarkus.test.security.TestSecurity; +import io.quarkus.test.security.jwt.Claim; +import io.quarkus.test.security.jwt.JwtSecurity; import io.restassured.RestAssured; @QuarkusTest @@ -896,11 +893,19 @@ import io.restassured.RestAssured; public class TestSecurityAuthTest { @Test - @TestSecurity(user = "userJwt", roles = "viewer", attributes = { - @SecurityAttribute(key = "claim.email", value = "user@gmail.com") - }) - public void testJwtWithDummyUser() { + @TestSecurity(user = "userJwt", roles = "viewer") + public void testJwt() { RestAssured.when().get("test-security-jwt").then() + .body(is("userJwt:viewer")); + } + + @Test + @TestSecurity(user = "userJwt", roles = "viewer") + @JwtSecurity(claims = { + @Claim(key = "email", value = "user@gmail.com") + }) + public void testJwtWithClaims() { + RestAssured.when().get("test-security-jwt-claims").then() .body(is("userJwt:viewer:user@gmail.com")); } @@ -911,16 +916,6 @@ where `ProtectedResource` class may look like this: [source, java] ---- -package io.quarkus.it.keycloak; - -import javax.inject.Inject; -import javax.ws.rs.GET; -import javax.ws.rs.Path; - -import org.eclipse.microprofile.jwt.JsonWebToken; -import io.quarkus.security.Authenticated; -import io.quarkus.security.identity.SecurityIdentity; - @Path("/web-app") @Authenticated public class ProtectedResource { @@ -930,14 +925,21 @@ public class ProtectedResource { @GET @Path("test-security-jwt") - public String testSecurityJwt() { + public String testSecurityOidc() { + return accessToken.getName() + ":" + accessToken.getGroups().iterator().next(); + } + + @GET + @Path("test-security-jwt-claims") + public String testSecurityOidcUserInfoMetadata() { return accessToken.getName() + ":" + accessToken.getGroups().iterator().next() + ":" + accessToken.getClaim("email"); } } ---- -Note that `TestSecurity` `user` property is returned as `JsonWebToken.getName()` and `roles` property - as `JsonWebToken.getGroups()`. Additionally, any `SecurityAttribute` with the key starting from `claim.` will be returned as a token claim value, for example, `claim.email` will support `JsonWebToken.getClaim("email")`, etc. +Note that `@TestSecurity` annotation must always be used and its `user` property is returned as `JsonWebToken.getName()` and `roles` property - as `JsonWebToken.getGroups()`. +`@JwtSecurity` annotation is optional and can be used to set the additional token claims. [[generate-jwt-tokens]] == Generate JWT tokens with SmallRye JWT @@ -949,7 +951,7 @@ Finally both the confidentiality and integrity of the claims can be further enfo SmallRye JWT provides an API for securing the JWT claims using all of these options. -== Maven dependency +=== Maven dependency [source,xml] ---- diff --git a/docs/src/main/asciidoc/security-openid-connect-web-authentication.adoc b/docs/src/main/asciidoc/security-openid-connect-web-authentication.adoc index b8bb02f3abc4a..3c661fc8b22b8 100644 --- a/docs/src/main/asciidoc/security-openid-connect-web-authentication.adoc +++ b/docs/src/main/asciidoc/security-openid-connect-web-authentication.adoc @@ -739,17 +739,7 @@ Default realm name is `quarkus` and client id - `quarkus-web-app` - set `keycloa [[integration-testing-security-annotation]] === TestSecurity annotation -Please see link:security-jwt#integration-testing-security-annotation[Use TestingSecurity with injected JsonWebToken] section for more information about using `@TestSecurity` for testing the `web-app` application endpoint code which depends on the injected ID and access `JsonWebToken`. - -The only difference is that the following dependency should be used when testing the `web-app` applications: -[source,xml] ----- - - io.quarkus - quarkus-test-security-oidc - test - ----- +Please see link:security-openid-connect#integration-testing-security-annotation[Use TestingSecurity with injected JsonWebToken] section for more information about using `@TestSecurity` and `@OidcSecurity` annotations for testing the `web-app` application endpoint code which depends on the injected ID and access `JsonWebToken` as well as `UserInfo` and `OidcConfigurationMetadata`. == Configuration Reference diff --git a/docs/src/main/asciidoc/security-openid-connect.adoc b/docs/src/main/asciidoc/security-openid-connect.adoc index 01951a1f89192..2820ff51a2663 100644 --- a/docs/src/main/asciidoc/security-openid-connect.adoc +++ b/docs/src/main/asciidoc/security-openid-connect.adoc @@ -678,9 +678,9 @@ This approach provides a more limited coverage compared to the Wiremock approach [[integration-testing-security-annotation]] === TestSecurity annotation -Please see link:security-jwt#integration-testing-security-annotation[Use TestingSecurity with injected JsonWebToken] section for more information about using `@TestSecurity` for testing the `service` application endpoint code which depends on the injected `JsonWebToken`. +You can use `@TestSecurity` and `@OidcSecurity` annotations for testing the `service` application endpoint code which depends on the injected `JsonWebToken` as well as `UserInfo` and `OidcConfigurationMetadata`. -The only difference is that the following dependency should be used when testing the `service` applications: +Add the following dependency: [source,xml] ---- @@ -690,6 +690,86 @@ The only difference is that the following dependency should be used when testing ---- +and write a test code like this one: + +[source, java] +---- +import static org.hamcrest.Matchers.is; +import org.junit.jupiter.api.Test; +import io.quarkus.test.common.http.TestHTTPEndpoint; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.security.TestSecurity; +import io.quarkus.test.security.oidc.Claim; +import io.quarkus.test.security.oidc.ConfigMetadata; +import io.quarkus.test.security.oidc.OidcSecurity; +import io.quarkus.test.security.oidc.UserInfo; +import io.restassured.RestAssured; + +@QuarkusTest +@TestHTTPEndpoint(ProtectedResource.class) +public class TestSecurityAuthTest { + + @Test + @TestSecurity(user = "userOidc", roles = "viewer") + public void testOidc() { + RestAssured.when().get("test-security-oidc").then() + .body(is("userOidc:viewer")); + } + + @Test + @TestSecurity(user = "userOidc", roles = "viewer") + @OidcSecurity(claims = { + @Claim(key = "email", value = "user@gmail.com") + }, userinfo = { + @UserInfo(key = "sub", value = "subject") + }, config = { + @ConfigMetadata(key = "issuer", value = "issuer") + }) + public void testOidcWithClaimsUserInfoAndMetadata() { + RestAssured.when().get("test-security-oidc-claims-userinfo-metadata").then() + .body(is("userOidc:viewer:user@gmail.com:subject:issuer")); + } + +} +---- + +where `ProtectedResource` class may look like this: + +[source, java] +---- +@Path("/web-app") +@Authenticated +public class ProtectedResource { + + @Inject + JsonWebToken accessToken; + @Inject + UserInfo userInfo; + @Inject + OidcConfigurationMetadata configMetadata; + + @GET + @Path("test-security-oidc") + public String testSecurityOidc() { + return accessToken.getName() + ":" + accessToken.getGroups().iterator().next(); + } + + @GET + @Path("test-security-oidc-claims-userinfo-metadata") + public String testSecurityOidcWithClaimsUserInfoMetadata() { + return accessToken.getName() + ":" + accessToken.getGroups().iterator().next() + + ":" + accessToken.getClaim("email") + + ":" + userInfo.getString("sub") + + ":" + configMetadata.get("issuer"); + } +} +---- + +Note that `@TestSecurity` annotation must always be used and its `user` property is returned as `JsonWebToken.getName()` and `roles` property - as `JsonWebToken.getGroups()`. +`@OidcSecurity` annotation is optional and can be used to set the additional token claims, as well as `UserInfo` and `OidcConfigurationMetadata` properties. +Additionally, if `quarkus.oidc.token.issuer` property is configured then it will be used as an `OidcConfigurationMetadata` `issuer` property value. + + == References * https://www.keycloak.org/documentation.html[Keycloak Documentation] diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/UserInfo.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/UserInfo.java index 57fb7fd660dce..5b5a851462e4d 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/UserInfo.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/UserInfo.java @@ -22,6 +22,10 @@ public UserInfo(String userInfoJson) { json = toJsonObject(userInfoJson); } + public UserInfo(JsonObject json) { + this.json = json; + } + public String getString(String name) { return json.getString(name); } diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcConfigurationMetadataProducer.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcConfigurationMetadataProducer.java index 68d408b3bc01a..f86e88a11bdea 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcConfigurationMetadataProducer.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcConfigurationMetadataProducer.java @@ -20,9 +20,9 @@ public class OidcConfigurationMetadataProducer { OidcConfigurationMetadata produce() { OidcConfigurationMetadata configMetadata = null; - if (!identity.isAnonymous()) { - configMetadata = (OidcConfigurationMetadata) identity.getAttribute(OidcUtils.CONFIG_METADATA_ATTRIBUTE); - } else if (tenantConfig.getDefaultTenant().oidcConfig.tenantEnabled) { + configMetadata = (OidcConfigurationMetadata) identity.getAttribute(OidcUtils.CONFIG_METADATA_ATTRIBUTE); + + if (configMetadata == null && tenantConfig.getDefaultTenant().oidcConfig.tenantEnabled) { configMetadata = tenantConfig.getDefaultTenant().provider.getMetadata(); } if (configMetadata == null) { diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcUtils.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcUtils.java index 8d7add91f246d..db3ac78f9d98e 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcUtils.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcUtils.java @@ -28,9 +28,9 @@ import io.vertx.ext.web.RoutingContext; public final class OidcUtils { - static final String CONFIG_METADATA_ATTRIBUTE = "configuration-metadata"; - static final String USER_INFO_ATTRIBUTE = "userinfo"; - static final String TENANT_ID_ATTRIBUTE = "tenant-id"; + public static final String CONFIG_METADATA_ATTRIBUTE = "configuration-metadata"; + public static final String USER_INFO_ATTRIBUTE = "userinfo"; + public static final String TENANT_ID_ATTRIBUTE = "tenant-id"; /** * This pattern uses a positive lookahead to split an expression around the forward slashes * ignoring those which are located inside a pair of the double quotes. diff --git a/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/ProtectedResource.java b/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/ProtectedResource.java index c6d39d48ff723..c116c2d6468da 100644 --- a/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/ProtectedResource.java +++ b/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/ProtectedResource.java @@ -18,6 +18,7 @@ import io.quarkus.oidc.OIDCException; import io.quarkus.oidc.OidcConfigurationMetadata; import io.quarkus.oidc.RefreshToken; +import io.quarkus.oidc.UserInfo; import io.quarkus.security.Authenticated; import io.quarkus.security.identity.SecurityIdentity; import io.vertx.ext.web.RoutingContext; @@ -48,6 +49,9 @@ public class ProtectedResource { @Inject RefreshToken refreshToken; + @Inject + UserInfo userInfo; + @Context SecurityContext securityContext; @@ -61,7 +65,9 @@ public String testSecurity() { @Path("test-security-oidc") public String testSecurityJwt() { return idToken.getName() + ":" + idToken.getGroups().iterator().next() - + ":" + idToken.getClaim("email"); + + ":" + idToken.getClaim("email") + + ":" + userInfo.getString("sub") + + ":" + configMetadata.get("audience"); } @GET diff --git a/integration-tests/oidc-code-flow/src/test/java/io/quarkus/it/keycloak/TestSecurityLazyAuthTest.java b/integration-tests/oidc-code-flow/src/test/java/io/quarkus/it/keycloak/TestSecurityLazyAuthTest.java index 53b0880a9cd6b..581226c075eaf 100644 --- a/integration-tests/oidc-code-flow/src/test/java/io/quarkus/it/keycloak/TestSecurityLazyAuthTest.java +++ b/integration-tests/oidc-code-flow/src/test/java/io/quarkus/it/keycloak/TestSecurityLazyAuthTest.java @@ -6,8 +6,11 @@ import io.quarkus.test.common.http.TestHTTPEndpoint; import io.quarkus.test.junit.QuarkusTest; -import io.quarkus.test.security.SecurityAttribute; import io.quarkus.test.security.TestSecurity; +import io.quarkus.test.security.oidc.Claim; +import io.quarkus.test.security.oidc.ConfigMetadata; +import io.quarkus.test.security.oidc.OidcSecurity; +import io.quarkus.test.security.oidc.UserInfo; import io.restassured.RestAssured; @QuarkusTest @@ -22,12 +25,17 @@ public void testWithDummyUser() { } @Test - @TestSecurity(user = "userOidc", roles = "viewer", attributes = { - @SecurityAttribute(key = "claim.email", value = "user@gmail.com") + @TestSecurity(user = "userOidc", roles = "viewer") + @OidcSecurity(claims = { + @Claim(key = "email", value = "user@gmail.com") + }, userinfo = { + @UserInfo(key = "sub", value = "subject") + }, config = { + @ConfigMetadata(key = "audience", value = "aud") }) public void testJwtWithDummyUser() { RestAssured.when().get("test-security-oidc").then() - .body(is("userOidc:viewer:user@gmail.com")); + .body(is("userOidc:viewer:user@gmail.com:subject:aud")); } } diff --git a/integration-tests/oidc/src/test/java/io/quarkus/it/keycloak/TestSecurityLazyAuthTest.java b/integration-tests/oidc/src/test/java/io/quarkus/it/keycloak/TestSecurityLazyAuthTest.java index 204b41c5d175d..fedf09826ab35 100644 --- a/integration-tests/oidc/src/test/java/io/quarkus/it/keycloak/TestSecurityLazyAuthTest.java +++ b/integration-tests/oidc/src/test/java/io/quarkus/it/keycloak/TestSecurityLazyAuthTest.java @@ -6,8 +6,9 @@ import io.quarkus.test.common.http.TestHTTPEndpoint; import io.quarkus.test.junit.QuarkusTest; -import io.quarkus.test.security.SecurityAttribute; import io.quarkus.test.security.TestSecurity; +import io.quarkus.test.security.oidc.Claim; +import io.quarkus.test.security.oidc.OidcSecurity; import io.restassured.RestAssured; @QuarkusTest @@ -22,8 +23,9 @@ public void testWithDummyUser() { } @Test - @TestSecurity(user = "userJwt", roles = "viewer", attributes = { - @SecurityAttribute(key = "claim.email", value = "user@gmail.com") + @TestSecurity(user = "userJwt", roles = "viewer") + @OidcSecurity(claims = { + @Claim(key = "email", value = "user@gmail.com") }) public void testJwtWithDummyUser() { RestAssured.when().get("test-security-jwt").then() diff --git a/integration-tests/smallrye-jwt-token-propagation/src/test/java/io/quarkus/it/keycloak/TestSecurityLazyAuthTest.java b/integration-tests/smallrye-jwt-token-propagation/src/test/java/io/quarkus/it/keycloak/TestSecurityLazyAuthTest.java index 204b41c5d175d..7054ce79da94b 100644 --- a/integration-tests/smallrye-jwt-token-propagation/src/test/java/io/quarkus/it/keycloak/TestSecurityLazyAuthTest.java +++ b/integration-tests/smallrye-jwt-token-propagation/src/test/java/io/quarkus/it/keycloak/TestSecurityLazyAuthTest.java @@ -6,8 +6,9 @@ import io.quarkus.test.common.http.TestHTTPEndpoint; import io.quarkus.test.junit.QuarkusTest; -import io.quarkus.test.security.SecurityAttribute; import io.quarkus.test.security.TestSecurity; +import io.quarkus.test.security.jwt.Claim; +import io.quarkus.test.security.jwt.JwtSecurity; import io.restassured.RestAssured; @QuarkusTest @@ -22,8 +23,9 @@ public void testWithDummyUser() { } @Test - @TestSecurity(user = "userJwt", roles = "viewer", attributes = { - @SecurityAttribute(key = "claim.email", value = "user@gmail.com") + @TestSecurity(user = "userJwt", roles = "viewer") + @JwtSecurity(claims = { + @Claim(key = "email", value = "user@gmail.com") }) public void testJwtWithDummyUser() { RestAssured.when().get("test-security-jwt").then() diff --git a/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/Claim.java b/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/Claim.java new file mode 100644 index 0000000000000..22c2c4c3ea32b --- /dev/null +++ b/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/Claim.java @@ -0,0 +1,13 @@ +package io.quarkus.test.security.jwt; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({}) +public @interface Claim { + String key(); + + String value(); +} diff --git a/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/JwtSecurity.java b/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/JwtSecurity.java new file mode 100644 index 0000000000000..622f7e2477ea8 --- /dev/null +++ b/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/JwtSecurity.java @@ -0,0 +1,13 @@ +package io.quarkus.test.security.jwt; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE, ElementType.METHOD }) +public @interface JwtSecurity { + + Claim[] claims() default {}; +} diff --git a/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/JwtTestSecurityIdentityAugmentorProducer.java b/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/JwtTestSecurityIdentityAugmentorProducer.java index 11e90403337cc..ef91b90b9e229 100644 --- a/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/JwtTestSecurityIdentityAugmentorProducer.java +++ b/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/JwtTestSecurityIdentityAugmentorProducer.java @@ -1,6 +1,6 @@ package io.quarkus.test.security.jwt; -import java.util.Map; +import java.lang.annotation.Annotation; import java.util.Set; import javax.enterprise.context.ApplicationScoped; @@ -26,9 +26,10 @@ public TestSecurityIdentityAugmentor produce() { private static class JwtTestSecurityIdentityAugmentor implements TestSecurityIdentityAugmentor { @Override - public SecurityIdentity augment(final SecurityIdentity identity) { + public SecurityIdentity augment(final SecurityIdentity identity, final Annotation[] annotations) { QuarkusSecurityIdentity.Builder builder = QuarkusSecurityIdentity.builder(identity); + final JwtSecurity jwtSecurity = findJwtSecurity(annotations); builder.setPrincipal(new JsonWebToken() { @Override @@ -42,9 +43,11 @@ public T getClaim(String claimName) { if (Claims.groups.name().equals(claimName)) { return (T) identity.getRoles(); } - for (Map.Entry entry : identity.getAttributes().entrySet()) { - if (entry.getKey().startsWith("claim." + claimName)) { - return (T) entry.getValue(); + if (jwtSecurity != null && jwtSecurity.claims() != null) { + for (Claim claim : jwtSecurity.claims()) { + if (claim.key().equals(claimName)) { + return (T) claim.value(); + } } } return null; @@ -59,5 +62,14 @@ public Set getClaimNames() { return builder.build(); } + + private JwtSecurity findJwtSecurity(Annotation[] annotations) { + for (Annotation ann : annotations) { + if (ann instanceof JwtSecurity) { + return (JwtSecurity) ann; + } + } + return null; + } } } diff --git a/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/Claim.java b/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/Claim.java new file mode 100644 index 0000000000000..a0a326a72e525 --- /dev/null +++ b/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/Claim.java @@ -0,0 +1,13 @@ +package io.quarkus.test.security.oidc; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({}) +public @interface Claim { + String key(); + + String value(); +} diff --git a/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/ConfigMetadata.java b/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/ConfigMetadata.java new file mode 100644 index 0000000000000..0d3da1e1aaa1f --- /dev/null +++ b/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/ConfigMetadata.java @@ -0,0 +1,13 @@ +package io.quarkus.test.security.oidc; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({}) +public @interface ConfigMetadata { + String key(); + + String value(); +} diff --git a/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/OidcSecurity.java b/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/OidcSecurity.java new file mode 100644 index 0000000000000..1f1d4ac973312 --- /dev/null +++ b/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/OidcSecurity.java @@ -0,0 +1,17 @@ +package io.quarkus.test.security.oidc; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE, ElementType.METHOD }) +public @interface OidcSecurity { + + Claim[] claims() default {}; + + UserInfo[] userinfo() default {}; + + ConfigMetadata[] config() default {}; +} diff --git a/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/OidcTestSecurityIdentityAugmentorProducer.java b/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/OidcTestSecurityIdentityAugmentorProducer.java index 080239157a7c7..7295011dc1f8f 100644 --- a/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/OidcTestSecurityIdentityAugmentorProducer.java +++ b/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/OidcTestSecurityIdentityAugmentorProducer.java @@ -1,11 +1,16 @@ package io.quarkus.test.security.oidc; -import java.util.Map; +import java.lang.annotation.Annotation; +import java.util.Optional; import java.util.stream.Collectors; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.inject.Produces; +import javax.inject.Inject; +import javax.json.Json; +import javax.json.JsonObjectBuilder; +import org.eclipse.microprofile.config.inject.ConfigProperty; import org.eclipse.microprofile.jwt.Claims; import org.eclipse.microprofile.jwt.JsonWebToken; import org.jose4j.jwt.JwtClaims; @@ -13,34 +18,43 @@ import io.quarkus.arc.Unremovable; import io.quarkus.oidc.AccessTokenCredential; import io.quarkus.oidc.IdTokenCredential; +import io.quarkus.oidc.OidcConfigurationMetadata; import io.quarkus.oidc.runtime.OidcJwtCallerPrincipal; +import io.quarkus.oidc.runtime.OidcUtils; import io.quarkus.security.identity.SecurityIdentity; import io.quarkus.security.runtime.QuarkusSecurityIdentity; import io.quarkus.test.security.TestSecurityIdentityAugmentor; import io.smallrye.jwt.build.Jwt; import io.smallrye.jwt.util.KeyUtils; +import io.vertx.core.json.JsonObject; @ApplicationScoped public class OidcTestSecurityIdentityAugmentorProducer { + @Inject + @ConfigProperty(name = "quarkus.oidc.token.issuer") + Optional issuer; + @Produces @Unremovable public TestSecurityIdentityAugmentor produce() { return new OidcTestSecurityIdentityAugmentor(); } - private static class OidcTestSecurityIdentityAugmentor implements TestSecurityIdentityAugmentor { + private class OidcTestSecurityIdentityAugmentor implements TestSecurityIdentityAugmentor { @Override - public SecurityIdentity augment(final SecurityIdentity identity) { + public SecurityIdentity augment(final SecurityIdentity identity, final Annotation[] annotations) { QuarkusSecurityIdentity.Builder builder = QuarkusSecurityIdentity.builder(identity); + final OidcSecurity oidcSecurity = findOidcSecurity(annotations); + // JsonWebToken JwtClaims claims = new JwtClaims(); claims.setClaim(Claims.preferred_username.name(), identity.getPrincipal().getName()); claims.setClaim(Claims.groups.name(), identity.getRoles().stream().collect(Collectors.toList())); - for (Map.Entry entry : identity.getAttributes().entrySet()) { - if (entry.getKey().startsWith("claim.")) { - claims.setClaim(entry.getKey().substring("claim.".length()), entry.getValue()); + if (oidcSecurity != null && oidcSecurity.claims() != null) { + for (Claim claim : oidcSecurity.claims()) { + claims.setClaim(claim.key(), claim.value()); } } String jwt = generateToken(claims); @@ -52,6 +66,27 @@ public SecurityIdentity augment(final SecurityIdentity identity) { builder.addCredential(idToken); builder.addCredential(accessToken); + // UserInfo + if (oidcSecurity != null && oidcSecurity.userinfo() != null) { + JsonObjectBuilder userInfoBuilder = Json.createObjectBuilder(); + for (UserInfo userinfo : oidcSecurity.userinfo()) { + userInfoBuilder.add(userinfo.key(), userinfo.value()); + } + builder.addAttribute(OidcUtils.USER_INFO_ATTRIBUTE, new io.quarkus.oidc.UserInfo(userInfoBuilder.build())); + } + + // OidcConfigurationMetadata + JsonObject configMetadataBuilder = new JsonObject(); + if (issuer.isPresent()) { + configMetadataBuilder.put("issuer", issuer.get()); + } + if (oidcSecurity != null && oidcSecurity.config() != null) { + for (ConfigMetadata config : oidcSecurity.config()) { + configMetadataBuilder.put(config.key(), config.value()); + } + } + builder.addAttribute(OidcUtils.CONFIG_METADATA_ATTRIBUTE, new OidcConfigurationMetadata(configMetadataBuilder)); + return builder.build(); } @@ -62,6 +97,15 @@ private String generateToken(JwtClaims claims) { throw new RuntimeException(ex); } } + + private OidcSecurity findOidcSecurity(Annotation[] annotations) { + for (Annotation ann : annotations) { + if (ann instanceof OidcSecurity) { + return (OidcSecurity) ann; + } + } + return null; + } } } diff --git a/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/UserInfo.java b/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/UserInfo.java new file mode 100644 index 0000000000000..3df8227c076c9 --- /dev/null +++ b/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/UserInfo.java @@ -0,0 +1,13 @@ +package io.quarkus.test.security.oidc; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({}) +public @interface UserInfo { + String key(); + + String value(); +} diff --git a/test-framework/security/src/main/java/io/quarkus/test/security/QuarkusSecurityTestExtension.java b/test-framework/security/src/main/java/io/quarkus/test/security/QuarkusSecurityTestExtension.java index 85d87d52f865f..676fde82020f5 100644 --- a/test-framework/security/src/main/java/io/quarkus/test/security/QuarkusSecurityTestExtension.java +++ b/test-framework/security/src/main/java/io/quarkus/test/security/QuarkusSecurityTestExtension.java @@ -1,5 +1,6 @@ package io.quarkus.test.security; +import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashSet; @@ -40,13 +41,22 @@ public void beforeEach(QuarkusTestMethodContext context) { throw new RuntimeException(e); } }).toArray(Class[]::new)); + Annotation[] allAnnotations = new Annotation[] {}; TestSecurity testSecurity = method.getAnnotation(TestSecurity.class); if (testSecurity == null) { testSecurity = original.getAnnotation(TestSecurity.class); + if (testSecurity != null) { + allAnnotations = original.getAnnotations(); + } while (testSecurity == null && original != Object.class) { original = original.getSuperclass(); testSecurity = original.getAnnotation(TestSecurity.class); + if (testSecurity != null) { + allAnnotations = original.getAnnotations(); + } } + } else { + allAnnotations = method.getAnnotations(); } if (testSecurity == null) { return; @@ -66,7 +76,7 @@ public void beforeEach(QuarkusTestMethodContext context) { .collect(Collectors.toMap(s -> s.key(), s -> s.value()))); } - SecurityIdentity userIdentity = augment(user.build()); + SecurityIdentity userIdentity = augment(user.build(), allAnnotations); CDI.current().select(TestIdentityAssociation.class).get().setTestIdentity(userIdentity); } } catch (Exception e) { @@ -75,10 +85,10 @@ public void beforeEach(QuarkusTestMethodContext context) { } - private SecurityIdentity augment(SecurityIdentity identity) { + private SecurityIdentity augment(SecurityIdentity identity, Annotation[] annotations) { Instance producer = CDI.current().select(TestSecurityIdentityAugmentor.class); if (producer.isResolvable()) { - return producer.get().augment(identity); + return producer.get().augment(identity, annotations); } return identity; } diff --git a/test-framework/security/src/main/java/io/quarkus/test/security/TestSecurityIdentityAugmentor.java b/test-framework/security/src/main/java/io/quarkus/test/security/TestSecurityIdentityAugmentor.java index 71af6f2c76acd..6c39853a17d67 100644 --- a/test-framework/security/src/main/java/io/quarkus/test/security/TestSecurityIdentityAugmentor.java +++ b/test-framework/security/src/main/java/io/quarkus/test/security/TestSecurityIdentityAugmentor.java @@ -1,7 +1,9 @@ package io.quarkus.test.security; +import java.lang.annotation.Annotation; + import io.quarkus.security.identity.SecurityIdentity; public interface TestSecurityIdentityAugmentor { - SecurityIdentity augment(SecurityIdentity identity); + SecurityIdentity augment(SecurityIdentity identity, Annotation[] annotations); } From 8d5cd6ea3a5d9e331d189ef3d3abdbc37947f9ad Mon Sep 17 00:00:00 2001 From: Rhuan Rocha Date: Sat, 13 Mar 2021 20:13:17 -0300 Subject: [PATCH 0023/2077] Fixing the optaplanner guide Signed-off-by: Rhuan Rocha --- docs/src/main/asciidoc/optaplanner.adoc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/src/main/asciidoc/optaplanner.adoc b/docs/src/main/asciidoc/optaplanner.adoc index 1ef8e6ecabad2..525a5a8cf8b00 100644 --- a/docs/src/main/asciidoc/optaplanner.adoc +++ b/docs/src/main/asciidoc/optaplanner.adoc @@ -445,13 +445,15 @@ public class TimeTableConstraintProvider implements ConstraintProvider { // A room can accommodate at most one lesson at the same time. // Select a lesson ... - return constraintFactory.from(Lesson.class) - // ... and pair it with another lesson ... + return constraintFactory + .from(Lesson.class) .join(Lesson.class, // ... in the same timeslot ... Joiners.equal(Lesson::getTimeslot), // ... in the same room ... - Joiners.equal(Lesson::getRoom)) + Joiners.equal(Lesson::getRoom), + // Avoiding repeated pairs (A -> B, B -> A) + Joiners.lessThan(Lesson::getId)) // then penalize each pair with a hard weight. .penalize("Room conflict", HardSoftScore.ONE_HARD); } From 5445d82d08f4518d72e5057bd9c8b1e8ba88e921 Mon Sep 17 00:00:00 2001 From: Erik Mattheis Date: Tue, 27 Apr 2021 16:43:12 -0400 Subject: [PATCH 0024/2077] added Amazon SSM extension based on pattern of KMS extension --- bom/application/pom.xml | 10 + .../java/io/quarkus/deployment/Feature.java | 1 + devtools/bom-descriptor-json/pom.xml | 13 + docs/pom.xml | 13 + docs/src/main/asciidoc/amazon-ssm.adoc | 363 ++++++++++++++++++ extensions/amazon-services/pom.xml | 1 + .../amazon-services/ssm/deployment/pom.xml | 77 ++++ .../amazon/ssm/deployment/SsmProcessor.java | 152 ++++++++ .../SsmSyncClientFullConfigTest.java | 31 ++ .../sync-urlconn-full-config.properties | 10 + extensions/amazon-services/ssm/pom.xml | 22 ++ .../amazon-services/ssm/runtime/pom.xml | 96 +++++ .../ssm/runtime/SsmBuildTimeConfig.java | 26 ++ .../amazon/ssm/runtime/SsmClientProducer.java | 52 +++ .../quarkus/amazon/ssm/runtime/SsmConfig.java | 42 ++ .../amazon/ssm/runtime/SsmRecorder.java | 73 ++++ .../resources/META-INF/quarkus-extension.yaml | 11 + integration-tests/amazon-services/pom.xml | 21 +- .../io/quarkus/it/amazon/ssm/SsmResource.java | 57 +++ .../src/main/resources/application.properties | 6 + .../io/quarkus/it/amazon/AmazonSsmITCase.java | 8 + .../io/quarkus/it/amazon/AmazonSsmTest.java | 22 ++ 22 files changed, 1106 insertions(+), 1 deletion(-) create mode 100644 docs/src/main/asciidoc/amazon-ssm.adoc create mode 100644 extensions/amazon-services/ssm/deployment/pom.xml create mode 100644 extensions/amazon-services/ssm/deployment/src/main/java/io/quarkus/amazon/ssm/deployment/SsmProcessor.java create mode 100644 extensions/amazon-services/ssm/deployment/src/test/java/io/quarkus/amazon/ssm/deployment/SsmSyncClientFullConfigTest.java create mode 100644 extensions/amazon-services/ssm/deployment/src/test/resources/sync-urlconn-full-config.properties create mode 100644 extensions/amazon-services/ssm/pom.xml create mode 100644 extensions/amazon-services/ssm/runtime/pom.xml create mode 100644 extensions/amazon-services/ssm/runtime/src/main/java/io/quarkus/amazon/ssm/runtime/SsmBuildTimeConfig.java create mode 100644 extensions/amazon-services/ssm/runtime/src/main/java/io/quarkus/amazon/ssm/runtime/SsmClientProducer.java create mode 100644 extensions/amazon-services/ssm/runtime/src/main/java/io/quarkus/amazon/ssm/runtime/SsmConfig.java create mode 100644 extensions/amazon-services/ssm/runtime/src/main/java/io/quarkus/amazon/ssm/runtime/SsmRecorder.java create mode 100644 extensions/amazon-services/ssm/runtime/src/main/resources/META-INF/quarkus-extension.yaml create mode 100644 integration-tests/amazon-services/src/main/java/io/quarkus/it/amazon/ssm/SsmResource.java create mode 100644 integration-tests/amazon-services/src/test/java/io/quarkus/it/amazon/AmazonSsmITCase.java create mode 100644 integration-tests/amazon-services/src/test/java/io/quarkus/it/amazon/AmazonSsmTest.java diff --git a/bom/application/pom.xml b/bom/application/pom.xml index b80a9d3893a60..62c8efb492ffb 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -1887,6 +1887,16 @@ quarkus-amazon-kms-deployment ${project.version} + + io.quarkus + quarkus-amazon-ssm + ${project.version} + + + io.quarkus + quarkus-amazon-ssm-deployment + ${project.version} + io.quarkus quarkus-amazon-iam diff --git a/core/deployment/src/main/java/io/quarkus/deployment/Feature.java b/core/deployment/src/main/java/io/quarkus/deployment/Feature.java index e2ae5f4760c9f..2c24476318071 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/Feature.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/Feature.java @@ -18,6 +18,7 @@ public enum Feature { AMAZON_SQS, AMAZON_SES, AMAZON_KMS, + AMAZON_SSM, ARTEMIS_CORE, ARTEMIS_JMS, CACHE, diff --git a/devtools/bom-descriptor-json/pom.xml b/devtools/bom-descriptor-json/pom.xml index d9d2d2120c00c..0a4c0c292ad4c 100644 --- a/devtools/bom-descriptor-json/pom.xml +++ b/devtools/bom-descriptor-json/pom.xml @@ -292,6 +292,19 @@ + + io.quarkus + quarkus-amazon-ssm + ${project.version} + pom + test + + + * + * + + + io.quarkus quarkus-apache-httpclient diff --git a/docs/pom.xml b/docs/pom.xml index b53b9950ed5b4..8bfd7e7878c6b 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -253,6 +253,19 @@ + + io.quarkus + quarkus-amazon-ssm-deployment + ${project.version} + pom + test + + + * + * + + + io.quarkus quarkus-apache-httpclient-deployment diff --git a/docs/src/main/asciidoc/amazon-ssm.adoc b/docs/src/main/asciidoc/amazon-ssm.adoc new file mode 100644 index 0000000000000..908a23b79779a --- /dev/null +++ b/docs/src/main/asciidoc/amazon-ssm.adoc @@ -0,0 +1,363 @@ +//// +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 +//// += Quarkus - Amazon SSM Client +:extension-status: preview + +include::./attributes.adoc[] + +AWS Systems Manager (formerly Amazon Simple Systems Manager, or SSM) is a service that you can use to view and control your infrastructure on AWS. +One of the most useful features of SSM for microservices is the https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html[Parameter Store], which provides secure, hierarchical storage for configuration data management and secrets management.. + +You can find more information about SSM at https://docs.aws.amazon.com/systems-manager/[the AWS Systems Manager website]. + +NOTE: The SSM extension is based on https://docs.aws.amazon.com/sdk-for-java/v2/developer-guide/welcome.html[AWS Java SDK 2.x]. +It's a major rewrite of the 1.x code base that offers two programming models (Blocking & Async). + +include::./status-include.adoc[] + +The Quarkus extension supports two programming models: + +* Blocking access using URL Connection HTTP client (by default) or the Apache HTTP Client +* https://docs.aws.amazon.com/sdk-for-java/v2/developer-guide/basics-async.html[Asynchronous programming] based on JDK's `CompletableFuture` objects and the Netty HTTP client. + +In this guide, we see how you can get your REST services to use SSM locally and on AWS. + +== Prerequisites + +To complete this guide, you need: + +* JDK 11+ installed with `JAVA_HOME` configured appropriately +* an IDE +* Apache Maven {maven-version} +* An AWS Account to access the SSM service +* Docker for your system to run SSM locally for testing purposes + +=== Set up SSM locally + +The easiest way to start working with SSM is to run a local instance as a container. + +[source,bash,subs="verbatim,attributes"] +---- +docker run --rm --name local-ssm --publish 8014:4583 -e SERVICES=ssm -e START_WEB=0 -d localstack/localstack:0.11.1 +---- +This starts a SSM instance that is accessible on port `8014`. + +Create an AWS profile for your local instance using AWS CLI: +[source,shell,subs="verbatim,attributes"] +---- +$ aws configure --profile localstack +AWS Access Key ID [None]: test-key +AWS Secret Access Key [None]: test-secret +Default region name [None]: us-east-1 +Default output format [None]: +---- + +== Solution +The application built here allows to store and retrieve parameters using the SSM parameter store. + +We recommend that you follow the instructions in the next sections and create the application step by step. +However, you can go right to the completed example. + +Clone the Git repository: `git clone {quickstarts-clone-url}`, or download an {quickstarts-archive-url}[archive]. + +The solution is located in the `amazon-ssm-quickstart` {quickstarts-tree-url}/amazon-ssm-quickstart[directory]. + +== Creating the Maven project + +First, we need a new project. Create a new project with the following command: + +[source,bash,subs=attributes+] +---- +mvn io.quarkus:quarkus-maven-plugin:{quarkus-version}:create \ + -DprojectGroupId=org.acme \ + -DprojectArtifactId=amazon-ssm-quickstart \ + -DclassName="org.acme.ssm.QuarkusSsmSyncResource" \ + -Dpath="/sync" \ + -Dextensions="resteasy,resteasy-jackson,amazon-ssm,resteasy-mutiny" +cd amazon-ssm-quickstart +---- + +This command generates a Maven structure importing the RESTEasy/JAX-RS, Mutiny and Amazon SSM Client extensions. +After this, the `amazon-ssm` extension has been added to your `pom.xml` as well as the Mutiny support for RESTEasy. + +== Creating JSON REST service + +In this example, we will create an application that allows us to store and retrieve parameters to and from SSM parameter store using a RESTful API. +The example application will demonstrate the two programming models supported by the extension. + +Let's start with an abstract `org.acme.ssm.QuarkusSsmResource` class to provide the common functionality we will need for both the synchronous and asynchrounous exposures. + +[source,java] +---- +package org.acme.ssm; + +import static java.lang.Boolean.TRUE; +import static java.util.stream.Collectors.toMap; + +import java.util.Map; +import java.util.stream.Collector; + +import javax.annotation.PostConstruct; + +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import software.amazon.awssdk.services.ssm.model.GetParameterRequest; +import software.amazon.awssdk.services.ssm.model.GetParametersByPathRequest; +import software.amazon.awssdk.services.ssm.model.Parameter; +import software.amazon.awssdk.services.ssm.model.ParameterType; +import software.amazon.awssdk.services.ssm.model.PutParameterRequest; + +public abstract class QuarkusSsmResource { + + @ConfigProperty(name = "parameters.path") <1> + String parametersPath; + + @PostConstruct <2> + void normalizePath() { + if (!parametersPath.startsWith("/")) { + parametersPath = "/" + parametersPath; + } + if (!parametersPath.endsWith("/")) { + parametersPath = parametersPath + "/"; + } + } + + protected Collector> parametersToMap() { <3> + return toMap(p -> p.name().substring(parametersPath.length()), Parameter::value); + } + + protected GetParametersByPathRequest generateGetParametersByPathRequest() { + return GetParametersByPathRequest.builder() <4> + .path(parametersPath) + .withDecryption(TRUE) + .build(); + } + + protected PutParameterRequest generatePutParameterRequest(String name, String value, boolean secure) { + return PutParameterRequest.builder() <5> + .name(parametersPath + name) + .value(value) + .type(secure ? ParameterType.SECURE_STRING : ParameterType.STRING) + .overwrite(TRUE) + .build(); + } + + protected GetParameterRequest generateGetParameterRequest(String name) { + return GetParameterRequest.builder() <6> + .name(parametersPath + name) + .withDecryption(TRUE) + .build(); + } +} +---- + +<1> Inject a configured path under which to store parameters +<2> Ensure the path starts and ends with `/` +<3> Collect parameters into a map of simple names and values +<4> Generate a request for all parameters under the configured path +<5> Generate a request to set a specific parameter +<6> Generate a request to get a specific parameter value + +Now, we can extend the class and create the synchronous implementation in the `org.acme.ssm.QuarkusSsmSyncResource` class. + +[source,java] +---- +package org.acme.ssm; + +import java.util.Map; + +import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.DefaultValue; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import software.amazon.awssdk.services.ssm.SsmClient; + +@Path("/sync") +public class QuarkusSsmSyncResource extends QuarkusSsmResource { + + @Inject <1> + SsmClient ssm; + + @GET + @Produces(MediaType.APPLICATION_JSON) + public Map getParameters() { + return ssm.getParametersByPath(generateGetParametersByPathRequest()) + .parameters().stream().collect(parametersToMap()); + } + + @PUT + @Path("/{name}") + @Consumes(MediaType.TEXT_PLAIN) + public void setParameter(@PathParam("name") String name, + @QueryParam("secure") @DefaultValue("false") boolean secure, + String value) { + + ssm.putParameter(generatePutParameterRequest(name, value, secure)); + } + + @GET + @Path("/{name}") + @Produces(MediaType.TEXT_PLAIN) + public String getParameter(@PathParam("name") String name) { + return ssm.getParameter(generateGetParameterRequest(name)) + .parameter().value(); + } +} +---- + +<1> Inject the client provided by the amazon-ssm extension + +Using the Amazon SSM SDK, we can easily store and retrieve arbitrary name/value pairs, and we can optionally store the values in a secure manner. + +== Configuring SSM clients + +Both SSM clients (sync and async) are configurable via the `application.properties` file that can be provided in the `src/main/resources` directory. +Additionally, you need to add to the classpath a proper implementation of the sync client. By default the extension uses the URL connection HTTP client, so +you need to add a URL connection client dependency to the `pom.xml` file: + +[source,xml] +---- + + software.amazon.awssdk + url-connection-client + +---- + +If you want to use Apache HTTP client instead, configure it as follows: + +[source,properties] +---- +quarkus.ssm.sync-client.type=apache +---- + +And add the following dependency to the application `pom.xml`: + +[source,xml] +---- + + software.amazon.awssdk + apache-client + + + io.quarkus + quarkus-apache-httpclient + +---- + +If you're going to use a local SSM instance, configure it as follows: + +[source,properties] +---- +quarkus.ssm.endpoint-override=http://localhost:8014 <1> + +quarkus.ssm.aws.region=us-east-1 <2> +quarkus.ssm.aws.credentials.type=static <3> +quarkus.ssm.aws.credentials.static-provider.access-key-id=test-key +quarkus.ssm.aws.credentials.static-provider.secret-access-key=test-secret +---- + +<1> Override the SSM client to use localstack instead of the actual AWS service +<2> Localstack defaults to `us-east-1` +<3> The `static` credentials provider lets you set the `access-key-id` and `secret-access-key` directly + +If you want to work with an AWS account, you can simply remove or comment out all Amazon SSM related properties. By default, the SSM client extension will use the `default` credentials provider chain that looks for credentials in this order: + +include::./amazon-credentials.adoc[] + +And the region from your AWS CLI profile will be used. + +== Next steps + +=== Packaging + +Packaging your application is as simple as `./mvnw clean package`. +It can then be run with `java -Dparameters.path=/quarkus/is/awesome/ -jar target/quarkus-app/quarkus-run.jar`. + +With GraalVM installed, you can also create a native executable binary: `./mvnw clean package -Dnative`. +Depending on your system, that will take some time. + +=== Going asynchronous + +Thanks to the AWS SDK v2.x used by the Quarkus extension, you can use the asynchronous programming model out of the box. + +Create a `org.acme.ssm.QuarkusSsmAsyncResource` REST resource that will be similar to our `QuarkusSsmSyncResource` but using an asynchronous programming model. + +[source,java] +---- +package org.acme.ssm; + +import java.util.Map; + +import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.DefaultValue; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import io.smallrye.mutiny.Uni; +import software.amazon.awssdk.services.ssm.SsmAsyncClient; + +@Path("/async") +public class QuarkusSsmAsyncResource extends QuarkusSsmResource { + + @Inject + SsmAsyncClient ssm; + + @GET + @Produces(MediaType.APPLICATION_JSON) + public Uni> getParameters() { + return Uni.createFrom().completionStage(ssm.getParametersByPath(generateGetParametersByPathRequest())) + .onItem().transform(r -> r.parameters().stream().collect(parametersToMap())); + } + + @PUT + @Path("/{name}") + @Consumes(MediaType.TEXT_PLAIN) + public Uni setParameter(@PathParam("name") String name, + @QueryParam("secure") @DefaultValue("false") boolean secure, + String value) { + + return Uni.createFrom().completionStage(ssm.putParameter(generatePutParameterRequest(name, value, secure))) + .onItem().transform(r -> null); + } + + @GET + @Path("/{name}") + @Produces(MediaType.TEXT_PLAIN) + public Uni getParameter(@PathParam("name") String name) { + return Uni.createFrom().completionStage(ssm.getParameter(generateGetParameterRequest(name))) + .onItem().transform(r -> r.parameter().value()); + } +} +---- + +Note that the `SsmAsyncClient` behaves just like the `SsmClient`, but returns `CompletionStage` objects which we use to create `Uni` instances, and then transform the emitted item. + +To enable the asynchronous client, we also need to add the Netty HTTP client dependency to the `pom.xml`: + +[source,xml] +---- + + software.amazon.awssdk + netty-nio-client + +---- + +== Configuration Reference + +include::{generated-dir}/config/quarkus-amazon-ssm.adoc[opts=optional, leveloffset=+1] diff --git a/extensions/amazon-services/pom.xml b/extensions/amazon-services/pom.xml index 128b00c01338a..149cf3c37006b 100644 --- a/extensions/amazon-services/pom.xml +++ b/extensions/amazon-services/pom.xml @@ -23,5 +23,6 @@ sqs ses kms + ssm diff --git a/extensions/amazon-services/ssm/deployment/pom.xml b/extensions/amazon-services/ssm/deployment/pom.xml new file mode 100644 index 0000000000000..2782f6abc4e24 --- /dev/null +++ b/extensions/amazon-services/ssm/deployment/pom.xml @@ -0,0 +1,77 @@ + + + 4.0.0 + + + io.quarkus + quarkus-amazon-ssm-parent + 999-SNAPSHOT + + + quarkus-amazon-ssm-deployment + Quarkus - Amazon Services - SSM - Deployment + + + + io.quarkus + quarkus-core-deployment + + + io.quarkus + quarkus-arc-deployment + + + io.quarkus + quarkus-netty-deployment + + + io.quarkus + quarkus-amazon-common-deployment + + + io.quarkus + quarkus-amazon-ssm + + + + + io.quarkus + quarkus-junit5-internal + test + + + io.rest-assured + rest-assured + test + + + software.amazon.awssdk + netty-nio-client + test + + + software.amazon.awssdk + url-connection-client + test + + + + + + + maven-compiler-plugin + + + + io.quarkus + quarkus-extension-processor + ${project.version} + + + + + + + diff --git a/extensions/amazon-services/ssm/deployment/src/main/java/io/quarkus/amazon/ssm/deployment/SsmProcessor.java b/extensions/amazon-services/ssm/deployment/src/main/java/io/quarkus/amazon/ssm/deployment/SsmProcessor.java new file mode 100644 index 0000000000000..3e7ac5d62e3a6 --- /dev/null +++ b/extensions/amazon-services/ssm/deployment/src/main/java/io/quarkus/amazon/ssm/deployment/SsmProcessor.java @@ -0,0 +1,152 @@ +package io.quarkus.amazon.ssm.deployment; + +import java.util.List; + +import org.jboss.jandex.DotName; + +import io.quarkus.amazon.common.deployment.AbstractAmazonServiceProcessor; +import io.quarkus.amazon.common.deployment.AmazonClientAsyncTransportBuildItem; +import io.quarkus.amazon.common.deployment.AmazonClientBuildItem; +import io.quarkus.amazon.common.deployment.AmazonClientBuilderBuildItem; +import io.quarkus.amazon.common.deployment.AmazonClientBuilderConfiguredBuildItem; +import io.quarkus.amazon.common.deployment.AmazonClientInterceptorsPathBuildItem; +import io.quarkus.amazon.common.deployment.AmazonClientSyncTransportBuildItem; +import io.quarkus.amazon.common.deployment.AmazonHttpClients; +import io.quarkus.amazon.common.runtime.AmazonClientApacheTransportRecorder; +import io.quarkus.amazon.common.runtime.AmazonClientNettyTransportRecorder; +import io.quarkus.amazon.common.runtime.AmazonClientRecorder; +import io.quarkus.amazon.common.runtime.AmazonClientUrlConnectionTransportRecorder; +import io.quarkus.amazon.ssm.runtime.SsmBuildTimeConfig; +import io.quarkus.amazon.ssm.runtime.SsmClientProducer; +import io.quarkus.amazon.ssm.runtime.SsmConfig; +import io.quarkus.amazon.ssm.runtime.SsmRecorder; +import io.quarkus.arc.deployment.AdditionalBeanBuildItem; +import io.quarkus.arc.deployment.BeanContainerBuildItem; +import io.quarkus.arc.deployment.BeanRegistrationPhaseBuildItem; +import io.quarkus.deployment.Feature; +import io.quarkus.deployment.annotations.BuildProducer; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.annotations.ExecutionTime; +import io.quarkus.deployment.annotations.Record; +import io.quarkus.deployment.builditem.ExtensionSslNativeSupportBuildItem; +import io.quarkus.deployment.builditem.FeatureBuildItem; +import io.quarkus.deployment.builditem.ShutdownContextBuildItem; +import software.amazon.awssdk.services.ssm.SsmAsyncClient; +import software.amazon.awssdk.services.ssm.SsmClient; + +public class SsmProcessor extends AbstractAmazonServiceProcessor { + + SsmBuildTimeConfig buildTimeConfig; + + @Override + protected Feature amazonServiceClientName() { + return Feature.AMAZON_SSM; + } + + @Override + protected String configName() { + return "ssm"; + } + + @Override + protected DotName syncClientName() { + return DotName.createSimple(SsmClient.class.getName()); + } + + @Override + protected DotName asyncClientName() { + return DotName.createSimple(SsmAsyncClient.class.getName()); + } + + @Override + protected String builtinInterceptorsPath() { + return "software/amazon/awssdk/services/ssm/execution.interceptors"; + } + + @BuildStep + AdditionalBeanBuildItem producer() { + return AdditionalBeanBuildItem.unremovableOf(SsmClientProducer.class); + } + + @BuildStep + void setup(BeanRegistrationPhaseBuildItem beanRegistrationPhase, + BuildProducer extensionSslNativeSupport, + BuildProducer feature, + BuildProducer interceptors, + BuildProducer clientProducer) { + + setupExtension(beanRegistrationPhase, extensionSslNativeSupport, feature, interceptors, clientProducer, + buildTimeConfig.sdk, buildTimeConfig.syncClient); + } + + @BuildStep(onlyIf = AmazonHttpClients.IsAmazonApacheHttpServicePresent.class) + @Record(ExecutionTime.RUNTIME_INIT) + void setupApacheSyncTransport(List amazonClients, SsmRecorder recorder, + AmazonClientApacheTransportRecorder transportRecorder, + SsmConfig runtimeConfig, BuildProducer syncTransports) { + + createApacheSyncTransportBuilder(amazonClients, + transportRecorder, + buildTimeConfig.syncClient, + recorder.getSyncConfig(runtimeConfig), + syncTransports); + } + + @BuildStep(onlyIf = AmazonHttpClients.IsAmazonUrlConnectionHttpServicePresent.class) + @Record(ExecutionTime.RUNTIME_INIT) + void setupUrlConnectionSyncTransport(List amazonClients, SsmRecorder recorder, + AmazonClientUrlConnectionTransportRecorder transportRecorder, + SsmConfig runtimeConfig, BuildProducer syncTransports) { + + createUrlConnectionSyncTransportBuilder(amazonClients, + transportRecorder, + buildTimeConfig.syncClient, + recorder.getSyncConfig(runtimeConfig), + syncTransports); + } + + @BuildStep(onlyIf = AmazonHttpClients.IsAmazonNettyHttpServicePresent.class) + @Record(ExecutionTime.RUNTIME_INIT) + void setupNettyAsyncTransport(List amazonClients, SsmRecorder recorder, + AmazonClientNettyTransportRecorder transportRecorder, + SsmConfig runtimeConfig, BuildProducer asyncTransports) { + + createNettyAsyncTransportBuilder(amazonClients, + transportRecorder, + recorder.getAsyncConfig(runtimeConfig), + asyncTransports); + } + + @BuildStep + @Record(ExecutionTime.RUNTIME_INIT) + void createClientBuilders(List syncTransports, + List asyncTransports, SsmRecorder recorder, + SsmConfig runtimeConfig, BuildProducer builderProducer) { + + createClientBuilders(syncTransports, asyncTransports, builderProducer, + (syncTransport) -> recorder.createSyncBuilder(runtimeConfig, syncTransport), + (asyncTransport) -> recorder.createAsyncBuilder(runtimeConfig, asyncTransport)); + } + + @BuildStep + @Record(ExecutionTime.RUNTIME_INIT) + void configureClient(List clients, SsmRecorder recorder, + AmazonClientRecorder commonRecorder, + SsmConfig runtimeConfig, + BuildProducer producer) { + + initClientBuilders(clients, commonRecorder, recorder.getAwsConfig(runtimeConfig), recorder.getSdkConfig(runtimeConfig), + buildTimeConfig.sdk, producer); + } + + @BuildStep + @Record(ExecutionTime.RUNTIME_INIT) + void buildClients(List configuredClients, SsmRecorder recorder, + BeanContainerBuildItem beanContainer, + ShutdownContextBuildItem shutdown) { + + buildClients(configuredClients, + (syncBuilder) -> recorder.buildClient(syncBuilder, beanContainer.getValue(), shutdown), + (asyncBuilder) -> recorder.buildAsyncClient(asyncBuilder, beanContainer.getValue(), shutdown)); + } +} diff --git a/extensions/amazon-services/ssm/deployment/src/test/java/io/quarkus/amazon/ssm/deployment/SsmSyncClientFullConfigTest.java b/extensions/amazon-services/ssm/deployment/src/test/java/io/quarkus/amazon/ssm/deployment/SsmSyncClientFullConfigTest.java new file mode 100644 index 0000000000000..6d80300b25cff --- /dev/null +++ b/extensions/amazon-services/ssm/deployment/src/test/java/io/quarkus/amazon/ssm/deployment/SsmSyncClientFullConfigTest.java @@ -0,0 +1,31 @@ +package io.quarkus.amazon.ssm.deployment; + +import javax.inject.Inject; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import software.amazon.awssdk.services.ssm.SsmAsyncClient; +import software.amazon.awssdk.services.ssm.SsmClient; + +public class SsmSyncClientFullConfigTest { + + @Inject + SsmClient client; + + @Inject + SsmAsyncClient async; + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addAsResource("sync-urlconn-full-config.properties", "application.properties")); + + @Test + public void test() { + // should finish with success + } +} diff --git a/extensions/amazon-services/ssm/deployment/src/test/resources/sync-urlconn-full-config.properties b/extensions/amazon-services/ssm/deployment/src/test/resources/sync-urlconn-full-config.properties new file mode 100644 index 0000000000000..70c6421513234 --- /dev/null +++ b/extensions/amazon-services/ssm/deployment/src/test/resources/sync-urlconn-full-config.properties @@ -0,0 +1,10 @@ +quarkus.ssm.endpoint-override=http://localhost:9090 + +quarkus.ssm.aws.region=us-east-1 +quarkus.ssm.aws.credentials.type=static +quarkus.ssm.aws.credentials.static-provider.access-key-id=test-key +quarkus.ssm.aws.credentials.static-provider.secret-access-key=test-secret + +quarkus.ssm.sync-client.type = url +quarkus.ssm.sync-client.connection-timeout = 0.100S +quarkus.ssm.sync-client.socket-timeout = 0.100S \ No newline at end of file diff --git a/extensions/amazon-services/ssm/pom.xml b/extensions/amazon-services/ssm/pom.xml new file mode 100644 index 0000000000000..e66077bfb737a --- /dev/null +++ b/extensions/amazon-services/ssm/pom.xml @@ -0,0 +1,22 @@ + + + 4.0.0 + + + io.quarkus + quarkus-amazon-services-parent + 999-SNAPSHOT + + + quarkus-amazon-ssm-parent + Quarkus - Amazon Services - SSM + pom + + + runtime + deployment + + + diff --git a/extensions/amazon-services/ssm/runtime/pom.xml b/extensions/amazon-services/ssm/runtime/pom.xml new file mode 100644 index 0000000000000..8828eee568f3a --- /dev/null +++ b/extensions/amazon-services/ssm/runtime/pom.xml @@ -0,0 +1,96 @@ + + + 4.0.0 + + + io.quarkus + quarkus-amazon-ssm-parent + 999-SNAPSHOT + + + quarkus-amazon-ssm + Quarkus - Amazon Services - SSM - Runtime + Connect to Amazon SSM + + + + io.quarkus + quarkus-core + + + io.quarkus + quarkus-arc + + + io.quarkus + quarkus-netty + + + + io.quarkus + quarkus-amazon-common + + + software.amazon.awssdk + ssm + + + + software.amazon.awssdk + netty-nio-client + + + software.amazon.awssdk + url-connection-client + + + software.amazon.awssdk + apache-client + + + + + software.amazon.awssdk + netty-nio-client + true + + + software.amazon.awssdk + url-connection-client + true + + + software.amazon.awssdk + apache-client + true + + + + org.jboss.logging + commons-logging-jboss-logging + + + + + + + io.quarkus + quarkus-bootstrap-maven-plugin + + + maven-compiler-plugin + + + + io.quarkus + quarkus-extension-processor + ${project.version} + + + + + + + diff --git a/extensions/amazon-services/ssm/runtime/src/main/java/io/quarkus/amazon/ssm/runtime/SsmBuildTimeConfig.java b/extensions/amazon-services/ssm/runtime/src/main/java/io/quarkus/amazon/ssm/runtime/SsmBuildTimeConfig.java new file mode 100644 index 0000000000000..d0268c49b39b7 --- /dev/null +++ b/extensions/amazon-services/ssm/runtime/src/main/java/io/quarkus/amazon/ssm/runtime/SsmBuildTimeConfig.java @@ -0,0 +1,26 @@ +package io.quarkus.amazon.ssm.runtime; + +import io.quarkus.amazon.common.runtime.SdkBuildTimeConfig; +import io.quarkus.amazon.common.runtime.SyncHttpClientBuildTimeConfig; +import io.quarkus.runtime.annotations.ConfigItem; +import io.quarkus.runtime.annotations.ConfigPhase; +import io.quarkus.runtime.annotations.ConfigRoot; + +/** + * Amazon SSM build time configuration + */ +@ConfigRoot(name = "ssm", phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) +public class SsmBuildTimeConfig { + + /** + * SDK client configurations for AWS SSM client + */ + @ConfigItem(name = ConfigItem.PARENT) + public SdkBuildTimeConfig sdk; + + /** + * Sync HTTP transport configuration for Amazon SSM client + */ + @ConfigItem + public SyncHttpClientBuildTimeConfig syncClient; +} diff --git a/extensions/amazon-services/ssm/runtime/src/main/java/io/quarkus/amazon/ssm/runtime/SsmClientProducer.java b/extensions/amazon-services/ssm/runtime/src/main/java/io/quarkus/amazon/ssm/runtime/SsmClientProducer.java new file mode 100644 index 0000000000000..88c168f13d8bd --- /dev/null +++ b/extensions/amazon-services/ssm/runtime/src/main/java/io/quarkus/amazon/ssm/runtime/SsmClientProducer.java @@ -0,0 +1,52 @@ +package io.quarkus.amazon.ssm.runtime; + +import javax.annotation.PreDestroy; +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Produces; + +import software.amazon.awssdk.services.ssm.SsmAsyncClient; +import software.amazon.awssdk.services.ssm.SsmAsyncClientBuilder; +import software.amazon.awssdk.services.ssm.SsmClient; +import software.amazon.awssdk.services.ssm.SsmClientBuilder; + +@ApplicationScoped +public class SsmClientProducer { + + private volatile SsmClientBuilder syncConfiguredBuilder; + private volatile SsmAsyncClientBuilder asyncConfiguredBuilder; + + private SsmClient client; + private SsmAsyncClient asyncClient; + + @Produces + @ApplicationScoped + public SsmClient client() { + client = syncConfiguredBuilder.build(); + return client; + } + + @Produces + @ApplicationScoped + public SsmAsyncClient asyncClient() { + asyncClient = asyncConfiguredBuilder.build(); + return asyncClient; + } + + @PreDestroy + public void destroy() { + if (client != null) { + client.close(); + } + if (asyncClient != null) { + asyncClient.close(); + } + } + + public void setSyncConfiguredBuilder(SsmClientBuilder syncConfiguredBuilder) { + this.syncConfiguredBuilder = syncConfiguredBuilder; + } + + public void setAsyncConfiguredBuilder(SsmAsyncClientBuilder asyncConfiguredBuilder) { + this.asyncConfiguredBuilder = asyncConfiguredBuilder; + } +} diff --git a/extensions/amazon-services/ssm/runtime/src/main/java/io/quarkus/amazon/ssm/runtime/SsmConfig.java b/extensions/amazon-services/ssm/runtime/src/main/java/io/quarkus/amazon/ssm/runtime/SsmConfig.java new file mode 100644 index 0000000000000..21c666f82844e --- /dev/null +++ b/extensions/amazon-services/ssm/runtime/src/main/java/io/quarkus/amazon/ssm/runtime/SsmConfig.java @@ -0,0 +1,42 @@ +package io.quarkus.amazon.ssm.runtime; + +import io.quarkus.amazon.common.runtime.AwsConfig; +import io.quarkus.amazon.common.runtime.NettyHttpClientConfig; +import io.quarkus.amazon.common.runtime.SdkConfig; +import io.quarkus.amazon.common.runtime.SyncHttpClientConfig; +import io.quarkus.runtime.annotations.ConfigDocSection; +import io.quarkus.runtime.annotations.ConfigItem; +import io.quarkus.runtime.annotations.ConfigPhase; +import io.quarkus.runtime.annotations.ConfigRoot; + +@ConfigRoot(name = "ssm", phase = ConfigPhase.RUN_TIME) +public class SsmConfig { + + /** + * AWS SDK client configurations + */ + @ConfigItem(name = ConfigItem.PARENT) + @ConfigDocSection + public SdkConfig sdk; + + /** + * AWS services configurations + */ + @ConfigItem + @ConfigDocSection + public AwsConfig aws; + + /** + * Sync HTTP transport configurations + */ + @ConfigItem + @ConfigDocSection + public SyncHttpClientConfig syncClient; + + /** + * Netty HTTP transport configurations + */ + @ConfigItem + @ConfigDocSection + public NettyHttpClientConfig asyncClient; +} diff --git a/extensions/amazon-services/ssm/runtime/src/main/java/io/quarkus/amazon/ssm/runtime/SsmRecorder.java b/extensions/amazon-services/ssm/runtime/src/main/java/io/quarkus/amazon/ssm/runtime/SsmRecorder.java new file mode 100644 index 0000000000000..b74a2aa26f90c --- /dev/null +++ b/extensions/amazon-services/ssm/runtime/src/main/java/io/quarkus/amazon/ssm/runtime/SsmRecorder.java @@ -0,0 +1,73 @@ +package io.quarkus.amazon.ssm.runtime; + +import io.quarkus.amazon.common.runtime.AwsConfig; +import io.quarkus.amazon.common.runtime.NettyHttpClientConfig; +import io.quarkus.amazon.common.runtime.SdkConfig; +import io.quarkus.amazon.common.runtime.SyncHttpClientConfig; +import io.quarkus.arc.runtime.BeanContainer; +import io.quarkus.runtime.RuntimeValue; +import io.quarkus.runtime.ShutdownContext; +import io.quarkus.runtime.annotations.Recorder; +import software.amazon.awssdk.awscore.client.builder.AwsClientBuilder; +import software.amazon.awssdk.http.SdkHttpClient; +import software.amazon.awssdk.http.async.SdkAsyncHttpClient; +import software.amazon.awssdk.services.ssm.SsmAsyncClient; +import software.amazon.awssdk.services.ssm.SsmAsyncClientBuilder; +import software.amazon.awssdk.services.ssm.SsmClient; +import software.amazon.awssdk.services.ssm.SsmClientBuilder; + +@Recorder +public class SsmRecorder { + + public RuntimeValue getSyncConfig(SsmConfig config) { + return new RuntimeValue<>(config.syncClient); + } + + public RuntimeValue getAsyncConfig(SsmConfig config) { + return new RuntimeValue<>(config.asyncClient); + } + + public RuntimeValue getAwsConfig(SsmConfig config) { + return new RuntimeValue<>(config.aws); + } + + public RuntimeValue getSdkConfig(SsmConfig config) { + return new RuntimeValue<>(config.sdk); + } + + public RuntimeValue createSyncBuilder(SsmConfig config, RuntimeValue transport) { + SsmClientBuilder builder = SsmClient.builder(); + if (transport != null) { + builder.httpClientBuilder(transport.getValue()); + } + return new RuntimeValue<>(builder); + } + + public RuntimeValue createAsyncBuilder(SsmConfig config, + RuntimeValue transport) { + + SsmAsyncClientBuilder builder = SsmAsyncClient.builder(); + if (transport != null) { + builder.httpClientBuilder(transport.getValue()); + } + return new RuntimeValue<>(builder); + } + + public RuntimeValue buildClient(RuntimeValue builder, + BeanContainer beanContainer, + ShutdownContext shutdown) { + SsmClientProducer producer = beanContainer.instance(SsmClientProducer.class); + producer.setSyncConfiguredBuilder((SsmClientBuilder) builder.getValue()); + shutdown.addShutdownTask(producer::destroy); + return new RuntimeValue<>(producer.client()); + } + + public RuntimeValue buildAsyncClient(RuntimeValue builder, + BeanContainer beanContainer, + ShutdownContext shutdown) { + SsmClientProducer producer = beanContainer.instance(SsmClientProducer.class); + producer.setAsyncConfiguredBuilder((SsmAsyncClientBuilder) builder.getValue()); + shutdown.addShutdownTask(producer::destroy); + return new RuntimeValue<>(producer.asyncClient()); + } +} diff --git a/extensions/amazon-services/ssm/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/amazon-services/ssm/runtime/src/main/resources/META-INF/quarkus-extension.yaml new file mode 100644 index 0000000000000..1c617de47fc13 --- /dev/null +++ b/extensions/amazon-services/ssm/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -0,0 +1,11 @@ +--- +name: "Amazon SSM" +metadata: + keywords: + - "ssm" + - "aws" + - "amazon" + guide: "https://quarkus.io/guides/amazon-ssm" + categories: + - "data" + status: "preview" diff --git a/integration-tests/amazon-services/pom.xml b/integration-tests/amazon-services/pom.xml index 487d753dfb432..8eb69b689a76f 100644 --- a/integration-tests/amazon-services/pom.xml +++ b/integration-tests/amazon-services/pom.xml @@ -21,6 +21,7 @@ http://localhost:8011 http://localhost:8012 http://localhost:8013 + http://localhost:8014 @@ -64,6 +65,10 @@ io.quarkus quarkus-amazon-kms + + io.quarkus + quarkus-amazon-ssm + software.amazon.awssdk netty-nio-client @@ -118,6 +123,19 @@ + + io.quarkus + quarkus-amazon-ssm-deployment + ${project.version} + pom + test + + + * + * + + + io.quarkus quarkus-amazon-s3-deployment @@ -303,7 +321,7 @@ aws-local-stack - s3,dynamodb,sns,sqs,kms,ses + s3,dynamodb,sns,sqs,kms,ssm,ses 0 @@ -314,6 +332,7 @@ 8011:4599 8012:4566 8013:4593 + 8014:4583 diff --git a/integration-tests/amazon-services/src/main/java/io/quarkus/it/amazon/ssm/SsmResource.java b/integration-tests/amazon-services/src/main/java/io/quarkus/it/amazon/ssm/SsmResource.java new file mode 100644 index 0000000000000..0d0ceeb658e93 --- /dev/null +++ b/integration-tests/amazon-services/src/main/java/io/quarkus/it/amazon/ssm/SsmResource.java @@ -0,0 +1,57 @@ +package io.quarkus.it.amazon.ssm; + +import static javax.ws.rs.core.MediaType.TEXT_PLAIN; + +import java.util.UUID; +import java.util.concurrent.CompletionStage; + +import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; + +import org.jboss.logging.Logger; + +import software.amazon.awssdk.services.ssm.SsmAsyncClient; +import software.amazon.awssdk.services.ssm.SsmClient; +import software.amazon.awssdk.services.ssm.model.GetParameterResponse; +import software.amazon.awssdk.services.ssm.model.Parameter; +import software.amazon.awssdk.services.ssm.model.ParameterType; + +@Path("/ssm") +public class SsmResource { + + private static final Logger LOG = Logger.getLogger(SsmResource.class); + public final static String TEXT = "Quarkus is awsome"; + private static final String SYNC_PARAM = "quarkus/sync-" + UUID.randomUUID().toString(); + private static final String ASYNC_PARAM = "quarkus/async-" + UUID.randomUUID().toString(); + + @Inject + SsmClient ssmClient; + + @Inject + SsmAsyncClient ssmAsyncClient; + + @GET + @Path("sync") + @Produces(TEXT_PLAIN) + public String testSync() { + LOG.info("Testing Sync SSM client with parameter: " + SYNC_PARAM); + //Put parameter + ssmClient.putParameter(r -> r.name(SYNC_PARAM).type(ParameterType.SECURE_STRING).value(TEXT)); + //Get parameter + return ssmClient.getParameter(r -> r.name(SYNC_PARAM).withDecryption(Boolean.TRUE)).parameter().value(); + } + + @GET + @Path("async") + @Produces(TEXT_PLAIN) + public CompletionStage testAsync() { + LOG.info("Testing Async SSM client with parameter: " + ASYNC_PARAM); + //Put and get parameter + return ssmAsyncClient.putParameter(r -> r.name(ASYNC_PARAM).type(ParameterType.SECURE_STRING).value(TEXT)) + .thenCompose(result -> ssmAsyncClient.getParameter(r -> r.name(ASYNC_PARAM).withDecryption(Boolean.TRUE))) + .thenApply(GetParameterResponse::parameter) + .thenApply(Parameter::value); + } +} diff --git a/integration-tests/amazon-services/src/main/resources/application.properties b/integration-tests/amazon-services/src/main/resources/application.properties index 66b1172506ce6..9bdb8d9282aa5 100644 --- a/integration-tests/amazon-services/src/main/resources/application.properties +++ b/integration-tests/amazon-services/src/main/resources/application.properties @@ -32,6 +32,12 @@ quarkus.kms.aws.credentials.type=static quarkus.kms.aws.credentials.static-provider.access-key-id=test-key quarkus.kms.aws.credentials.static-provider.secret-access-key=test-secret +quarkus.ssm.endpoint-override=${ssm.url} +quarkus.ssm.aws.region=us-east-1 +quarkus.ssm.aws.credentials.type=static +quarkus.ssm.aws.credentials.static-provider.access-key-id=test-key +quarkus.ssm.aws.credentials.static-provider.secret-access-key=test-secret + quarkus.ses.endpoint-override=${ses.url} quarkus.ses.aws.region=us-east-1 quarkus.ses.aws.credentials.type=static diff --git a/integration-tests/amazon-services/src/test/java/io/quarkus/it/amazon/AmazonSsmITCase.java b/integration-tests/amazon-services/src/test/java/io/quarkus/it/amazon/AmazonSsmITCase.java new file mode 100644 index 0000000000000..6f43157f0932d --- /dev/null +++ b/integration-tests/amazon-services/src/test/java/io/quarkus/it/amazon/AmazonSsmITCase.java @@ -0,0 +1,8 @@ +package io.quarkus.it.amazon; + +import io.quarkus.test.junit.NativeImageTest; + +@NativeImageTest +public class AmazonSsmITCase extends AmazonSsmTest { + +} diff --git a/integration-tests/amazon-services/src/test/java/io/quarkus/it/amazon/AmazonSsmTest.java b/integration-tests/amazon-services/src/test/java/io/quarkus/it/amazon/AmazonSsmTest.java new file mode 100644 index 0000000000000..26a431ad5ef84 --- /dev/null +++ b/integration-tests/amazon-services/src/test/java/io/quarkus/it/amazon/AmazonSsmTest.java @@ -0,0 +1,22 @@ +package io.quarkus.it.amazon; + +import static org.hamcrest.Matchers.is; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; +import io.restassured.RestAssured; + +@QuarkusTest +public class AmazonSsmTest { + + @Test + public void testSsmAsync() { + RestAssured.when().get("/test/ssm/async").then().body(is("Quarkus is awsome")); + } + + @Test + public void testSsmSync() { + RestAssured.when().get("/test/ssm/sync").then().body(is("Quarkus is awsome")); + } +} From 31ee43da9a6bcc0a535d644a628c07f70e99bbd7 Mon Sep 17 00:00:00 2001 From: Julien Ponge Date: Mon, 10 May 2021 15:52:09 +0200 Subject: [PATCH 0025/2077] Upgrade to Mutiny 0.17.0 and Smallrye Reactive Utils 2.5.1 Also align to Kotlin coroutines 1.4.3 --- bom/application/pom.xml | 6 +++--- .../keycloak/pep/test/ProtectedResource.java | 4 ++-- .../mongodb/reactive/ReactiveMongoClientTest.java | 14 +++++++------- .../interceptor/TransactionalInterceptorBase.java | 2 +- independent-projects/qute/pom.xml | 2 +- independent-projects/resteasy-reactive/pom.xml | 2 +- .../resteasy-reactive-kotlin/prod-mode/pom.xml | 1 - 7 files changed, 15 insertions(+), 16 deletions(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index b80a9d3893a60..64e5bcdab3557 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -52,7 +52,7 @@ 3.1.1 1.2.0 1.0.13 - 2.3.0 + 2.5.1 3.2.0 1.2.1 1.3.5 @@ -139,7 +139,7 @@ 4.1.60.Final 1.0.3 3.4.1.Final - 0.16.0 + 0.17.0 2.3.0 2.8.0 3.5.7 @@ -155,7 +155,7 @@ 2.38.1 1.4.2 1.4.32 - 1.4.2 + 1.4.3 2.1.2 0.10.0 3.0.1 diff --git a/extensions/keycloak-authorization/deployment/src/test/java/io/quarkus/keycloak/pep/test/ProtectedResource.java b/extensions/keycloak-authorization/deployment/src/test/java/io/quarkus/keycloak/pep/test/ProtectedResource.java index 920c145a6b57a..33a7d42dad4a6 100644 --- a/extensions/keycloak-authorization/deployment/src/test/java/io/quarkus/keycloak/pep/test/ProtectedResource.java +++ b/extensions/keycloak-authorization/deployment/src/test/java/io/quarkus/keycloak/pep/test/ProtectedResource.java @@ -31,8 +31,8 @@ public class ProtectedResource { @GET @Produces(MediaType.APPLICATION_JSON) public Uni> permissions() { - return identity.checkPermission(new AuthPermission("Permission Resource")).onItem() - .apply(new Function>() { + return identity.checkPermission(new AuthPermission("Permission Resource")) + .onItem().transform(new Function>() { @Override public List apply(Boolean granted) { if (granted) { diff --git a/extensions/mongodb-client/runtime/src/test/java/io/quarkus/mongodb/reactive/ReactiveMongoClientTest.java b/extensions/mongodb-client/runtime/src/test/java/io/quarkus/mongodb/reactive/ReactiveMongoClientTest.java index 42ab75cee9376..c4f0a7561fce5 100644 --- a/extensions/mongodb-client/runtime/src/test/java/io/quarkus/mongodb/reactive/ReactiveMongoClientTest.java +++ b/extensions/mongodb-client/runtime/src/test/java/io/quarkus/mongodb/reactive/ReactiveMongoClientTest.java @@ -45,7 +45,7 @@ void testFindOneReturnsObjectWithId() { ReactiveMongoCollection myCollection = database.getCollection(collection); Document document = createDoc(); myCollection.insertOne(document) - .then(() -> myCollection.find(eq("foo", "bar")).collect().first()) + .chain(() -> myCollection.find(eq("foo", "bar")).collect().first()) .invoke(found -> { assertThat(found).isNotNull(); assertThat(found.getObjectId("_id")).isNotNull(); @@ -60,7 +60,7 @@ void testFindOneReturnsEmptyWhenNonMatches() { ReactiveMongoCollection myCollection = database.getCollection(collection); Document document = createDoc(); myCollection.insertOne(document) - .then(() -> myCollection.find(eq("nothing", "missing")).collect().first()) + .chain(() -> myCollection.find(eq("nothing", "missing")).collect().first()) .invoke(opt -> assertThat(opt).isNull()) .await().indefinitely(); } @@ -122,7 +122,7 @@ void testFindBatch() { } List documents = new CopyOnWriteArrayList<>(); myCollection.insertMany(toBeInserted) - .then(() -> myCollection.find(new FindOptions().sort(eq("foo", 1))) + .chain(() -> myCollection.find(new FindOptions().sort(eq("foo", 1))) .onItem().invoke(documents::add) .onItem().ignoreAsUni()) .await().indefinitely(); @@ -143,7 +143,7 @@ void testFindBatchWithClass() { } List documents = new CopyOnWriteArrayList<>(); myCollection.insertMany(toBeInserted) - .then(() -> myCollection.find(Document.class, new FindOptions().sort(eq("foo", 1))) + .chain(() -> myCollection.find(Document.class, new FindOptions().sort(eq("foo", 1))) .onItem().invoke(documents::add) .onItem().ignoreAsUni()) .await().indefinitely(); @@ -164,7 +164,7 @@ void testFindBatchWithFilter() { } List documents = new CopyOnWriteArrayList<>(); myCollection.insertMany(toBeInserted) - .then(() -> myCollection.find(new FindOptions().filter(eq("num", 123)).sort(eq("foo", 1))) + .chain(() -> myCollection.find(new FindOptions().filter(eq("num", 123)).sort(eq("foo", 1))) .onItem().invoke(documents::add) .onItem().ignoreAsUni()) .await().indefinitely(); @@ -185,7 +185,7 @@ void testFindBatchWithFilterAndClass() { } List documents = new CopyOnWriteArrayList<>(); myCollection.insertMany(toBeInserted) - .then(() -> myCollection.find(Document.class, + .chain(() -> myCollection.find(Document.class, new FindOptions().filter(eq("num", 123)).sort(eq("foo", 1))) .onItem().invoke(documents::add) .onItem().ignoreAsUni()) @@ -264,7 +264,7 @@ void testAggregate() { pipeline.add(doc4); Optional optional = client.getDatabase(DATABASE).createCollection(collection) - .then(() -> insertDocs(client, collection, numDocs)) + .chain(() -> insertDocs(client, collection, numDocs)) .onItem().transformToMulti(x -> client.getDatabase(DATABASE).getCollection(collection).aggregate(pipeline)) .collect().first() .onItem().transform(doc -> doc.getInteger("foo_starting_with_bar1")) diff --git a/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/interceptor/TransactionalInterceptorBase.java b/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/interceptor/TransactionalInterceptorBase.java index fe79dfe920312..6910628258eaa 100644 --- a/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/interceptor/TransactionalInterceptorBase.java +++ b/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/interceptor/TransactionalInterceptorBase.java @@ -215,7 +215,7 @@ protected Object handleAsync(TransactionManager tm, Transaction tx, InvocationCo if (t instanceof RuntimeException) throw (RuntimeException) t; throw new RuntimeException(t); - }).on().termination(() -> { + }).onTermination().invoke(() -> { try { doInTransaction(tm, tx, () -> endTransaction(tm, tx, () -> { })); diff --git a/independent-projects/qute/pom.xml b/independent-projects/qute/pom.xml index 0320216ae4233..67b098de50670 100644 --- a/independent-projects/qute/pom.xml +++ b/independent-projects/qute/pom.xml @@ -41,7 +41,7 @@ 3.4.1.Final 3.0.0-M5 1.6.8 - 0.16.0 + 0.17.0 diff --git a/independent-projects/resteasy-reactive/pom.xml b/independent-projects/resteasy-reactive/pom.xml index 4c80dbc14a0fe..9371042a7256b 100644 --- a/independent-projects/resteasy-reactive/pom.xml +++ b/independent-projects/resteasy-reactive/pom.xml @@ -50,7 +50,7 @@ 1.6.8 2.0.1.Final 1.1.6 - 0.16.0 + 0.17.0 1.6.0 4.0.3 4.3.3 diff --git a/integration-tests/resteasy-reactive-kotlin/prod-mode/pom.xml b/integration-tests/resteasy-reactive-kotlin/prod-mode/pom.xml index 7c2d2b218000c..909c0e8f70db5 100644 --- a/integration-tests/resteasy-reactive-kotlin/prod-mode/pom.xml +++ b/integration-tests/resteasy-reactive-kotlin/prod-mode/pom.xml @@ -45,7 +45,6 @@ org.jetbrains.kotlinx kotlinx-coroutines-core-jvm - 1.4.2 org.jetbrains.kotlin From 17766ab139a0f6096f9be232b389b7de9cc5f10a Mon Sep 17 00:00:00 2001 From: Christopher Chianelli Date: Wed, 10 Mar 2021 13:52:35 -0500 Subject: [PATCH 0026/2077] Add ConstraintVerifier infomation to OptaPlanner documentation --- docs/src/main/asciidoc/optaplanner.adoc | 71 +++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/docs/src/main/asciidoc/optaplanner.adoc b/docs/src/main/asciidoc/optaplanner.adoc index 07c9843d9b7d5..ad9f6469e7ef0 100644 --- a/docs/src/main/asciidoc/optaplanner.adoc +++ b/docs/src/main/asciidoc/optaplanner.adoc @@ -713,6 +713,77 @@ On the server side, the `info` log show what OptaPlanner did in those five secon === Test the application +==== Test the constraints + +To test each constraint in isolation, use a `ConstraintVerifier` in unit tests. This tests each constraint's corner cases in isolation from the other tests, which lowers maintenance when adding a new constraint with proper test coverage. + +Add a `optaplanner-test` dependency in your `pom.xml`: +[source,xml] +---- + + org.optaplanner + optaplanner-test + test + +---- + +Create the `src/test/java/org/acme/optaplanner/solver/TimeTableConstraintProviderTest.java` class: +[source,java] +---- +package org.acme.optaplanner.solver; + +import java.time.DayOfWeek; +import java.time.LocalTime; + +import javax.inject.Inject; + +import io.quarkus.test.junit.QuarkusTest; +import org.acme.optaplanner.domain.Lesson; +import org.acme.optaplanner.domain.Room; +import org.acme.optaplanner.domain.TimeTable; +import org.acme.optaplanner.domain.Timeslot; +import org.junit.jupiter.api.Test; +import org.optaplanner.test.api.score.stream.ConstraintVerifier; + +@QuarkusTest +class TimeTableConstraintProviderTest { + + private static final Room ROOM = new Room("Room1"); + private static final Timeslot TIMESLOT1 = new Timeslot(DayOfWeek.MONDAY, LocalTime.of(9,0), LocalTime.NOON); + private static final Timeslot TIMESLOT2 = new Timeslot(DayOfWeek.TUESDAY, LocalTime.of(9,0), LocalTime.NOON); + + @Inject + ConstraintVerifier constraintVerifier; + + @Test + void roomConflict() { + Lesson firstLesson = new Lesson(1, "Subject1", "Teacher1", "Group1"); + Lesson conflictingLesson = new Lesson(2, "Subject2", "Teacher2", "Group2"); + Lesson nonConflictingLesson = new Lesson(3, "Subject3", "Teacher3", "Group3"); + + firstLesson.setRoom(ROOM); + firstLesson.setTimeslot(TIMESLOT1); + + conflictingLesson.setRoom(ROOM); + conflictingLesson.setTimeslot(TIMESLOT1); + + nonConflictingLesson.setRoom(ROOM); + nonConflictingLesson.setTimeslot(TIMESLOT2); + + constraintVerifier.verifyThat(TimeTableConstraintProvider::roomConflict) + .given(firstLesson, conflictingLesson, nonConflictingLesson) + .penalizesBy(1); + } + +} +---- + +This test verifies that the constraint `TimeTableConstraintProvider::roomConflict`, when given three lessons in the same room, where two lessons have the same timeslot, it penalizes with a match weight of `1`. So with a constraint weight of `10hard` it would reduce the score by `-10hard`. + +Notice how `ConstraintVerifier` ignores the constraint weight during testing - even if those constraint weights are hard coded in the `ConstraintProvider` - because constraints weights change regularly before going into production. This way, constraint weight tweaking does not break the unit tests. + +==== Test the solver + A good application includes test coverage. In a JUnit test, generate a test dataset and send it to the `TimeTableResource` to solve. From b72c5a52925fda88a0bc928f61afdd0dffb827ac Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Tue, 11 May 2021 15:35:48 +0200 Subject: [PATCH 0027/2077] Qute reflection resolver - support methods with params --- .../io/quarkus/qute/AccessorCandidate.java | 13 ++ .../java/io/quarkus/qute/EvaluatedParams.java | 8 +- .../java/io/quarkus/qute/FieldAccessor.java | 39 ++++++ .../java/io/quarkus/qute/FieldWrapper.java | 25 ---- .../java/io/quarkus/qute/GetterAccessor.java | 39 ++++++ .../main/java/io/quarkus/qute/MemberKey.java | 55 ++++---- .../java/io/quarkus/qute/MemberWrapper.java | 23 ---- .../java/io/quarkus/qute/MethodWrapper.java | 25 ---- .../io/quarkus/qute/MethodsCandidate.java | 60 +++++++++ .../quarkus/qute/ReflectionValueResolver.java | 120 ++++++++++-------- .../java/io/quarkus/qute/ValueAccessor.java | 19 +++ .../quarkus/qute/ReflectionResolverTest.java | 53 +++++++- 12 files changed, 313 insertions(+), 166 deletions(-) create mode 100644 independent-projects/qute/core/src/main/java/io/quarkus/qute/AccessorCandidate.java create mode 100644 independent-projects/qute/core/src/main/java/io/quarkus/qute/FieldAccessor.java delete mode 100644 independent-projects/qute/core/src/main/java/io/quarkus/qute/FieldWrapper.java create mode 100644 independent-projects/qute/core/src/main/java/io/quarkus/qute/GetterAccessor.java delete mode 100644 independent-projects/qute/core/src/main/java/io/quarkus/qute/MemberWrapper.java delete mode 100644 independent-projects/qute/core/src/main/java/io/quarkus/qute/MethodWrapper.java create mode 100644 independent-projects/qute/core/src/main/java/io/quarkus/qute/MethodsCandidate.java create mode 100644 independent-projects/qute/core/src/main/java/io/quarkus/qute/ValueAccessor.java diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/AccessorCandidate.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/AccessorCandidate.java new file mode 100644 index 0000000000000..277289b68febc --- /dev/null +++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/AccessorCandidate.java @@ -0,0 +1,13 @@ +package io.quarkus.qute; + +@FunctionalInterface +interface AccessorCandidate { + + /** + * + * @param context + * @return an accessor, is never null + */ + ValueAccessor getAccessor(EvalContext context); + +} diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/EvaluatedParams.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/EvaluatedParams.java index addba66417c8b..9c1278aee5023 100644 --- a/independent-projects/qute/core/src/main/java/io/quarkus/qute/EvaluatedParams.java +++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/EvaluatedParams.java @@ -79,15 +79,15 @@ public static EvaluatedParams evaluateMessageParams(EvalContext context) { return new EvaluatedParams(CompletableFuture.allOf(results), results); } - public final CompletionStage stage; + public final CompletionStage stage; private final CompletableFuture[] results; - EvaluatedParams(CompletionStage stage) { + EvaluatedParams(CompletionStage stage) { this.stage = stage; this.results = new CompletableFuture[] { stage.toCompletableFuture() }; } - EvaluatedParams(CompletionStage stage, CompletableFuture[] results) { + EvaluatedParams(CompletionStage stage, CompletableFuture[] results) { this.stage = stage; this.results = results; } @@ -132,7 +132,7 @@ public boolean parameterTypesMatch(boolean varargs, Class[] types) throws Int return false; } if (types.length > ++i) { - paramType = types[i]; + paramType = boxType(types[i]); } } return true; diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/FieldAccessor.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/FieldAccessor.java new file mode 100644 index 0000000000000..738acd97224a5 --- /dev/null +++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/FieldAccessor.java @@ -0,0 +1,39 @@ +package io.quarkus.qute; + +import java.lang.reflect.Field; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +/** + * + * @see ReflectionValueResolver + */ +class FieldAccessor implements ValueAccessor, AccessorCandidate { + + private final Field field; + + FieldAccessor(Field field) { + this.field = field; + } + + @SuppressWarnings("unchecked") + @Override + public CompletionStage getValue(Object instance) { + try { + Object ret = field.get(instance); + if (ret instanceof CompletionStage) { + return (CompletionStage) ret; + } else { + return CompletableFuture.completedFuture(ret); + } + } catch (Exception e) { + throw new IllegalStateException("Reflection invocation error", e); + } + } + + @Override + public ValueAccessor getAccessor(EvalContext context) { + return this; + } + +} diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/FieldWrapper.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/FieldWrapper.java deleted file mode 100644 index 050fafd602226..0000000000000 --- a/independent-projects/qute/core/src/main/java/io/quarkus/qute/FieldWrapper.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.quarkus.qute; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; - -/** - * - * @author Martin Kouba - */ -class FieldWrapper implements MemberWrapper { - - private final Field field; - - FieldWrapper(Field field) { - super(); - this.field = field; - } - - @Override - public Object getValue(Object instance) throws IllegalAccessException, - IllegalArgumentException, InvocationTargetException { - return field.get(instance); - } - -} diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/GetterAccessor.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/GetterAccessor.java new file mode 100644 index 0000000000000..100e352961804 --- /dev/null +++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/GetterAccessor.java @@ -0,0 +1,39 @@ +package io.quarkus.qute; + +import java.lang.reflect.Method; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +/** + * + * @see ReflectionValueResolver + */ +class GetterAccessor implements ValueAccessor, AccessorCandidate { + + private final Method method; + + GetterAccessor(Method method) { + this.method = method; + } + + @SuppressWarnings("unchecked") + @Override + public CompletionStage getValue(Object instance) { + try { + Object ret = method.invoke(instance); + if (ret instanceof CompletionStage) { + return (CompletionStage) ret; + } else { + return CompletableFuture.completedFuture(ret); + } + } catch (Exception e) { + throw new IllegalStateException("Reflection invocation error", e); + } + } + + @Override + public ValueAccessor getAccessor(EvalContext context) { + return this; + } + +} diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/MemberKey.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/MemberKey.java index 75d269ec27d93..2a7f08d513a09 100644 --- a/independent-projects/qute/core/src/main/java/io/quarkus/qute/MemberKey.java +++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/MemberKey.java @@ -1,73 +1,62 @@ package io.quarkus.qute; +import java.util.Objects; + /** * - * @author Martin Kouba + * @see ReflectionValueResolver */ final class MemberKey { - private final Class clazz; - - private final String name; - - public Class getClazz() { - return clazz; - } - - public String getName() { - return name; - } + final Class clazz; + final String name; + final int numberOfParams; - MemberKey(Class clazz, String name) { + MemberKey(Class clazz, String name, int numberOfParams) { this.clazz = clazz; this.name = name; + this.numberOfParams = numberOfParams; } @Override public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + ((clazz == null) ? 0 : clazz.hashCode()); - result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + clazz.hashCode(); + result = prime * result + name.hashCode(); + result = prime * result + numberOfParams; return result; } @Override public boolean equals(Object obj) { - if (this == obj) + if (this == obj) { return true; - if (obj == null) + } + if (obj == null) { return false; - if (!(obj instanceof MemberKey)) + } + if (getClass() != obj.getClass()) { return false; + } MemberKey other = (MemberKey) obj; - if (clazz == null) { - if (other.clazz != null) - return false; - } else if (!clazz.equals(other.clazz)) - return false; - if (name == null) { - if (other.name != null) - return false; - } else if (!name.equals(other.name)) - return false; - return true; + return Objects.equals(clazz, other.clazz) && Objects.equals(name, other.name) && numberOfParams == other.numberOfParams; } @Override public String toString() { - return String.format("MemberKey [clazz: %s, name: %s]", clazz, name); + return String.format("MemberKey [clazz: %s, name: %s, numberOfParams: %s]", clazz, name, numberOfParams); } - static MemberKey newInstance(Object contextObject, String name) { + static MemberKey from(Object contextObject, String name, int numberOfParams) { if (contextObject instanceof Class) { Class clazz = (Class) contextObject; if (clazz.isEnum() && ("values".equals(name) || isConstantName(clazz, name))) { // Special handling for enums - allows to access values() and constants - return new MemberKey(clazz, name); + return new MemberKey(clazz, name, numberOfParams); } } - return new MemberKey(contextObject.getClass(), name); + return new MemberKey(contextObject.getClass(), name, numberOfParams); } private static boolean isConstantName(Class enumClazz, String name) { diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/MemberWrapper.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/MemberWrapper.java deleted file mode 100644 index 39103a591b6b0..0000000000000 --- a/independent-projects/qute/core/src/main/java/io/quarkus/qute/MemberWrapper.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.quarkus.qute; - -import java.lang.reflect.InvocationTargetException; - -/** - * - * @author Martin Kouba - */ -@FunctionalInterface -interface MemberWrapper { - - /** - * - * @param instance - * @return the member value for the given instance - * @throws IllegalAccessException - * @throws IllegalArgumentException - * @throws InvocationTargetException - */ - Object getValue(Object instance) throws IllegalAccessException, - IllegalArgumentException, InvocationTargetException; - -} diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/MethodWrapper.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/MethodWrapper.java deleted file mode 100644 index bd76d61f52903..0000000000000 --- a/independent-projects/qute/core/src/main/java/io/quarkus/qute/MethodWrapper.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.quarkus.qute; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * - * @author Martin Kouba - */ -class MethodWrapper implements MemberWrapper { - - private final Method method; - - MethodWrapper(Method method) { - super(); - this.method = method; - } - - @Override - public Object getValue(Object instance) throws IllegalAccessException, - IllegalArgumentException, InvocationTargetException { - return method.invoke(instance); - } - -} diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/MethodsCandidate.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/MethodsCandidate.java new file mode 100644 index 0000000000000..7b62e90a1ea25 --- /dev/null +++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/MethodsCandidate.java @@ -0,0 +1,60 @@ +package io.quarkus.qute; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +/** + * + * @see ReflectionValueResolver + */ +final class MethodsCandidate implements AccessorCandidate { + + private final List methods; + + public MethodsCandidate(List methods) { + this.methods = methods; + } + + @Override + public ValueAccessor getAccessor(EvalContext context) { + EvaluatedParams params = EvaluatedParams.evaluate(context); + return new ValueAccessor() { + @Override + public CompletionStage getValue(Object instance) { + CompletableFuture result = new CompletableFuture<>(); + params.stage.whenComplete((r, t) -> { + if (t != null) { + result.completeExceptionally(t); + } else { + for (Method method : methods) { + try { + if (params.parameterTypesMatch(method.isVarArgs(), method.getParameterTypes())) { + Object[] args = new Object[method.getParameterCount()]; + for (int i = 0; i < args.length; i++) { + if (method.isVarArgs() && (i == args.length - 1)) { + Class lastParam = method.getParameterTypes()[i]; + args[i] = params.getVarargsResults(method.getParameterCount(), + lastParam.getComponentType()); + } else { + args[i] = params.getResult(i); + } + } + result.complete(method.invoke(instance, args)); + return; + } + } catch (Exception e) { + result.completeExceptionally(e); + } + } + // No method matches the parameter types + result.complete(Results.NOT_FOUND); + } + }); + return result; + } + }; + } + +} diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/ReflectionValueResolver.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/ReflectionValueResolver.java index b73328237337e..abc9984b11af4 100644 --- a/independent-projects/qute/core/src/main/java/io/quarkus/qute/ReflectionValueResolver.java +++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/ReflectionValueResolver.java @@ -7,21 +7,24 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Objects; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +/** + * This value resolver can be used to access public members of classes via reflection. + */ public class ReflectionValueResolver implements ValueResolver { /** * Lazy loading cache of lookup attempts (contains both hits and misses) */ - private final ConcurrentMap> memberCache = new ConcurrentHashMap<>(); + private final ConcurrentMap> candidates = new ConcurrentHashMap<>(); - private static final MemberWrapper ARRAY_GET_LENGTH = Array::getLength; + private static final AccessorCandidate ARRAY_GET_LENGTH = ec -> instance -> CompletableFuture + .completedFuture(Array.getLength(instance)); public static final String GET_PREFIX = "get"; public static final String IS_PREFIX = "is"; @@ -38,67 +41,59 @@ public boolean appliesTo(EvalContext context) { if (base == null) { return false; } - return memberCache.computeIfAbsent(MemberKey.newInstance(base, context.getName()), ReflectionValueResolver::findWrapper) - .isPresent(); + // Check if there is a member with the given name and number of params + return candidates.computeIfAbsent(MemberKey.from(base, context.getName(), context.getParams().size()), + this::findCandidate).isPresent(); } @Override public CompletionStage resolve(EvalContext context) { Object base = context.getBase(); - MemberKey key = MemberKey.newInstance(base, context.getName()); - MemberWrapper wrapper = memberCache.computeIfAbsent(key, ReflectionValueResolver::findWrapper).orElse(null); - - if (wrapper == null) { + MemberKey key = MemberKey.from(base, context.getName(), context.getParams().size()); + // At this point the candidate for the given key should be already computed + AccessorCandidate candidate = candidates.get(key).orElse(null); + if (candidate == null) { return Results.NOT_FOUND; } - - try { - return CompletableFuture.completedFuture(wrapper.getValue(base)); - } catch (Exception e) { - throw new IllegalStateException("Reflection invocation error", e); + ValueAccessor accessor = candidate.getAccessor(context); + if (accessor == null) { + return Results.NOT_FOUND; } + return accessor.getValue(base); } - public void clearMemberCache() { - memberCache.clear(); + public void clearCache() { + candidates.clear(); } - private static Optional findWrapper(MemberKey key) { - - if (key.getClazz().isArray()) { - if (key.getName().equals("length")) { + private Optional findCandidate(MemberKey key) { + if (key.clazz.isArray()) { + if (key.name.equals("length") && key.numberOfParams == 0) { return Optional.of(ARRAY_GET_LENGTH); } else { return Optional.empty(); } } - - Method foundMethod = findMethod(key.getClazz(), key.getName()); - - if (foundMethod != null) { - if (!foundMethod.isAccessible()) { - foundMethod.setAccessible(true); + if (key.numberOfParams > 0) { + List methods = findMethods(key.clazz, key.name, key.numberOfParams); + return methods.isEmpty() ? Optional.empty() : Optional.of(new MethodsCandidate(methods)); + } else { + Method foundMethod = findMethodNoArgs(key.clazz, key.name); + if (foundMethod != null) { + foundMethod.trySetAccessible(); + return Optional.of(new GetterAccessor(foundMethod)); } - return Optional.of(new MethodWrapper(foundMethod)); - } - - // Find public field - Field foundField = findField(key.getClazz(), key.getName()); - - if (foundField != null) { - if (!foundField.isAccessible()) { - foundField.setAccessible(true); + Field foundField = findField(key.clazz, key.name); + if (foundField != null) { + foundField.trySetAccessible(); + return Optional.of(new FieldAccessor(foundField)); } - return Optional.of(new FieldWrapper(foundField)); } // Member not found return Optional.empty(); } - private static Method findMethod(Class clazz, String name) { - Objects.requireNonNull(clazz); - Objects.requireNonNull(name); - + private Method findMethodNoArgs(Class clazz, String name) { Method foundMatch = null; Method foundGetterMatch = null; Method foundBooleanMatch = null; @@ -141,20 +136,8 @@ private static Method findMethod(Class clazz, String name) { return foundMatch; } - /** - * Tries to find a public field with the given name on the given class. - * - * @param clazz - * @param name - * @return the found field or null - */ - private static Field findField(Class clazz, String name) { - - Objects.requireNonNull(clazz); - Objects.requireNonNull(name); - + private Field findField(Class clazz, String name) { Field found = null; - for (Field field : clazz.getFields()) { if (field.getName().equals(name)) { found = field; @@ -163,9 +146,38 @@ private static Field findField(Class clazz, String name) { return found; } + private static List findMethods(Class clazz, String name, int numberOfParams) { + List foundMatch = new ArrayList<>(); + + List> hierarchy = new ArrayList<>(); + Collections.addAll(hierarchy, clazz.getInterfaces()); + Class superClass = clazz.getSuperclass(); + while (superClass != null) { + Collections.addAll(hierarchy, superClass.getInterfaces()); + superClass = superClass.getSuperclass(); + } + hierarchy.add(clazz); + + for (Class clazzToTest : hierarchy) { + for (Method method : clazzToTest.getMethods()) { + if (!Modifier.isPublic(method.getModifiers()) + || (!method.isVarArgs() && method.getParameterCount() != numberOfParams) + || method.getReturnType().equals(Void.TYPE) + || Object.class.equals(method.getDeclaringClass()) + || method.isBridge() + || !name.equals(method.getName())) { + continue; + } + foundMatch.add(method); + method.trySetAccessible(); + } + } + return foundMatch.size() == 1 ? Collections.singletonList(foundMatch.get(0)) : foundMatch; + } + private static boolean isMethodValid(Method method) { return method != null && Modifier.isPublic(method.getModifiers()) - && method.getParameterTypes().length == 0 + && method.getParameterCount() == 0 && !method.getReturnType().equals(Void.TYPE) && !Object.class.equals(method.getDeclaringClass()); } diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/ValueAccessor.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/ValueAccessor.java new file mode 100644 index 0000000000000..eb4c4480383b2 --- /dev/null +++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/ValueAccessor.java @@ -0,0 +1,19 @@ +package io.quarkus.qute; + +import java.util.concurrent.CompletionStage; + +/** + * + * @see ReflectionValueResolver + */ +@FunctionalInterface +interface ValueAccessor { + + /** + * + * @param instance + * @return the value + */ + CompletionStage getValue(Object instance); + +} diff --git a/independent-projects/qute/core/src/test/java/io/quarkus/qute/ReflectionResolverTest.java b/independent-projects/qute/core/src/test/java/io/quarkus/qute/ReflectionResolverTest.java index e9223aa693683..0387dde17c0de 100644 --- a/independent-projects/qute/core/src/test/java/io/quarkus/qute/ReflectionResolverTest.java +++ b/independent-projects/qute/core/src/test/java/io/quarkus/qute/ReflectionResolverTest.java @@ -4,6 +4,7 @@ import java.util.Map; import java.util.TreeMap; +import java.util.stream.IntStream; import org.junit.jupiter.api.Test; public class ReflectionResolverTest { @@ -13,8 +14,56 @@ public void testReflectionResolver() { Map treeMap = new TreeMap<>(Integer::compare); treeMap.put(2, "bar"); treeMap.put(1, "foo"); - assertEquals("foo", Engine.builder().addDefaults().addValueResolver(new ReflectionValueResolver()).build() - .parse("{map.entrySet.iterator.next.value}").data("map", treeMap).render()); + assertEquals("foo::o", Engine.builder().addDefaults().addValueResolver(new ReflectionValueResolver()).build() + .parse("{map.entrySet.iterator.next.value}::{str.charAt(1)}").data("map", treeMap, "str", "foo").render()); + } + + @Test + public void testFieldAccessor() { + assertEquals("box", Engine.builder().addDefaults().addValueResolver(new ReflectionValueResolver()).build() + .parse("{foo.name}").data("foo", new Foo("box")).render()); + } + + @Test + public void testMethodWithParameter() { + assertEquals("3", Engine.builder().addDefaults().addValueResolver(new ReflectionValueResolver()).build() + .parse("{foo.computeLength(foo.name)}").data("foo", new Foo("box")).render()); + } + + @Test + public void testMethodWithParameterNotFound() { + assertEquals("NOT_FOUND", Engine.builder().addDefaults().addValueResolver(new ReflectionValueResolver()).build() + .parse("{foo.computeLength(true)}").data("foo", new Foo("box")).render()); + } + + @Test + public void testMethodWithVarargs() { + assertEquals("box:box:", Engine.builder().addDefaults().addValueResolver(new ReflectionValueResolver()).build() + .parse("{foo.compute(foo.name,1,2)}").data("foo", new Foo("box")).render()); + } + + public static class Foo { + + public final String name; + + public Foo(String name) { + this.name = name; + } + + public int computeLength(String val) { + return val.length(); + } + + public int computeLength(Double val) { + return val.intValue(); + } + + public String compute(String val, int... counts) { + StringBuilder builder = new StringBuilder(); + IntStream.of(counts).forEach(i -> builder.append(val).append(":")); + return builder.toString(); + } + } } From 7da6493000c09c58807ec659a4616ea067862dc2 Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Mon, 10 May 2021 12:55:35 +0200 Subject: [PATCH 0028/2077] ArC - build fails if an injection point of raw type Instance is defined - this behavior is defined by the spec --- .../java/io/quarkus/arc/processor/Beans.java | 10 +++-- .../test/instance/RawTypeInstanceTest.java | 38 +++++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/instance/RawTypeInstanceTest.java diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Beans.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Beans.java index 1db503483ffcf..8e3a960fdc4e9 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Beans.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Beans.java @@ -454,15 +454,19 @@ static void resolveInjectionPoint(BeanDeployment deployment, InjectionTargetInfo } BuiltinBean builtinBean = BuiltinBean.resolve(injectionPoint); if (builtinBean != null) { - if (BuiltinBean.INJECTION_POINT.equals(builtinBean) + if (BuiltinBean.INJECTION_POINT == builtinBean && (target.kind() != TargetKind.BEAN || !BuiltinScope.DEPENDENT.is(target.asBean().getScope()))) { errors.add(new DefinitionException("Only @Dependent beans can access metadata about an injection point: " + injectionPoint.getTargetInfo())); - } - if (BuiltinBean.EVENT_METADATA.equals(builtinBean) + } else if (BuiltinBean.EVENT_METADATA == builtinBean && target.kind() != TargetKind.OBSERVER) { errors.add(new DefinitionException("EventMetadata can be only injected into an observer method: " + injectionPoint.getTargetInfo())); + } else if (BuiltinBean.INSTANCE == builtinBean + && injectionPoint.getRequiredType().kind() != Kind.PARAMETERIZED_TYPE) { + errors.add( + new DefinitionException("An injection point of raw type javax.enterprise.inject.Instance is defined: " + + injectionPoint.getTargetInfo())); } // Skip built-in beans return; diff --git a/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/instance/RawTypeInstanceTest.java b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/instance/RawTypeInstanceTest.java new file mode 100644 index 0000000000000..1706ac92adb64 --- /dev/null +++ b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/instance/RawTypeInstanceTest.java @@ -0,0 +1,38 @@ +package io.quarkus.arc.test.instance; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import io.quarkus.arc.test.ArcTestContainer; +import javax.enterprise.inject.Instance; +import javax.enterprise.inject.spi.DefinitionException; +import javax.inject.Inject; +import javax.inject.Singleton; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +public class RawTypeInstanceTest { + + @RegisterExtension + public ArcTestContainer container = ArcTestContainer.builder().beanClasses(Alpha.class).shouldFail().build(); + + @Test + public void testDefinitionError() { + Throwable failure = container.getFailure(); + assertNotNull(failure); + assertEquals(DefinitionException.class, failure.getClass()); + assertTrue(failure.getMessage().contains(Instance.class.getName())); + assertTrue(failure.getMessage().contains("Alpha#instance")); + } + + @Singleton + static class Alpha { + + @SuppressWarnings("rawtypes") + @Inject + Instance instance; + + } + +} From 307ebf1fc9475073a5130af4c1a03323ee37f3e2 Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Mon, 10 May 2021 11:53:44 +0200 Subject: [PATCH 0029/2077] gRPC - fail the build if an unsupported client stub is injected - resolves #17062 - also rename GrpcServiceBuildItem to GrpcClientBuildItem - Mutiny generated stub now implements the MutinyStub marker interface --- .../grpc/deployment/GrpcClientBuildItem.java | 80 ++++++++++ .../grpc/deployment/GrpcClientProcessor.java | 144 ++++++++++-------- .../quarkus/grpc/deployment/GrpcDotNames.java | 5 + .../grpc/deployment/GrpcServiceBuildItem.java | 30 ---- .../grpc/client/InvalidInjectionTypeTest.java | 45 ++++++ .../src/main/resources/MutinyStub.mustache | 2 +- .../io/quarkus/grpc/runtime/MutinyStub.java | 8 + 7 files changed, 222 insertions(+), 92 deletions(-) create mode 100644 extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcClientBuildItem.java delete mode 100644 extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcServiceBuildItem.java create mode 100644 extensions/grpc/deployment/src/test/java/io/quarkus/grpc/client/InvalidInjectionTypeTest.java create mode 100644 extensions/grpc/stubs/src/main/java/io/quarkus/grpc/runtime/MutinyStub.java diff --git a/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcClientBuildItem.java b/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcClientBuildItem.java new file mode 100644 index 0000000000000..27ad357e9972e --- /dev/null +++ b/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcClientBuildItem.java @@ -0,0 +1,80 @@ +package io.quarkus.grpc.deployment; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +import org.jboss.jandex.DotName; + +import io.quarkus.builder.item.MultiBuildItem; + +public final class GrpcClientBuildItem extends MultiBuildItem { + + private final String name; + private final Set stubs; + + public GrpcClientBuildItem(String name) { + this.name = name; + this.stubs = new HashSet<>(); + } + + public Set getStubs() { + return stubs; + } + + public void addStub(DotName stubClass, StubType type) { + stubs.add(new StubInfo(stubClass, type)); + } + + public String getServiceName() { + return name; + } + + public static final class StubInfo { + + public final DotName className; + public final StubType type; + + public StubInfo(DotName className, StubType type) { + this.className = className; + this.type = type; + } + + @Override + public int hashCode() { + return Objects.hash(className); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + StubInfo other = (StubInfo) obj; + return Objects.equals(className, other.className); + } + + } + + public enum StubType { + + BLOCKING("newBlockingStub"), + MUTINY("newMutinyStub"); + + private final String factoryMethodName; + + StubType(String factoryMethodName) { + this.factoryMethodName = factoryMethodName; + } + + public String getFactoryMethodName() { + return factoryMethodName; + } + } +} diff --git a/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcClientProcessor.java b/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcClientProcessor.java index 7c2074cb35c5c..c347990f8f4d7 100644 --- a/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcClientProcessor.java +++ b/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcClientProcessor.java @@ -6,8 +6,10 @@ import static io.quarkus.grpc.deployment.ResourceRegistrationUtils.registerResourcesForProperties; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Consumer; import java.util.regex.Pattern; @@ -19,8 +21,9 @@ import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.AnnotationTarget.Kind; import org.jboss.jandex.AnnotationValue; -import org.jboss.jandex.ClassType; +import org.jboss.jandex.ClassInfo; import org.jboss.jandex.DotName; +import org.jboss.jandex.IndexView; import org.jboss.jandex.MethodParameterInfo; import org.jboss.jandex.Type; import org.jboss.logging.Logger; @@ -28,11 +31,12 @@ import io.grpc.Channel; import io.quarkus.arc.deployment.AdditionalBeanBuildItem; import io.quarkus.arc.deployment.BeanDiscoveryFinishedBuildItem; -import io.quarkus.arc.deployment.BeanRegistrationPhaseBuildItem; -import io.quarkus.arc.processor.BeanConfigurator; +import io.quarkus.arc.deployment.SyntheticBeanBuildItem; +import io.quarkus.arc.processor.DotNames; import io.quarkus.arc.processor.InjectionPointInfo; import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.builditem.CombinedIndexBuildItem; import io.quarkus.deployment.builditem.FeatureBuildItem; import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem; import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem; @@ -40,6 +44,8 @@ import io.quarkus.gizmo.MethodDescriptor; import io.quarkus.gizmo.ResultHandle; import io.quarkus.grpc.GrpcClient; +import io.quarkus.grpc.deployment.GrpcClientBuildItem.StubInfo; +import io.quarkus.grpc.deployment.GrpcClientBuildItem.StubType; import io.quarkus.grpc.runtime.GrpcClientInterceptorContainer; import io.quarkus.grpc.runtime.supports.Channels; import io.quarkus.grpc.runtime.supports.GrpcClientConfigProvider; @@ -64,10 +70,11 @@ void registerBeans(BuildProducer beans) { @BuildStep void discoverInjectedGrpcServices(BeanDiscoveryFinishedBuildItem beanDiscovery, - BuildProducer services, - BuildProducer features) { + BuildProducer services, + BuildProducer features, + CombinedIndexBuildItem index) { - Map items = new HashMap<>(); + Map items = new HashMap<>(); for (InjectionPointInfo injectionPoint : beanDiscovery.getInjectionPoints()) { AnnotationInstance clientAnnotation = injectionPoint.getRequiredQualifier(GrpcDotNames.GRPC_CLIENT); @@ -104,52 +111,85 @@ void discoverInjectedGrpcServices(BeanDiscoveryFinishedBuildItem beanDiscovery, "Invalid @GrpcClient `" + injectionPoint.getTargetInfo() + "` - service name cannot be empty"); } - GrpcServiceBuildItem item; + GrpcClientBuildItem item; if (items.containsKey(serviceName)) { item = items.get(serviceName); } else { - item = new GrpcServiceBuildItem(serviceName); + item = new GrpcClientBuildItem(serviceName); items.put(serviceName, item); } Type injectionType = injectionPoint.getRequiredType(); - ClassType type; - if (injectionType.kind() == Type.Kind.PARAMETERIZED_TYPE) { - // Instance - type = injectionType.asParameterizedType().arguments().get(0).asClassType(); - } else { - // X directly - type = injectionType.asClassType(); + + // Programmatic lookup - take the param type + if (DotNames.INSTANCE.equals(injectionType.name()) || DotNames.INJECTABLE_INSTANCE.equals(injectionType.name())) { + injectionType = injectionType.asParameterizedType().arguments().get(0); } - if (!type.name().equals(GrpcDotNames.CHANNEL)) { - item.addStubClass(type); + + if (injectionType.name().equals(GrpcDotNames.CHANNEL)) { + // No need to add the stub class for Channel + continue; } - } - items.values().forEach(new Consumer() { - @Override - public void accept(GrpcServiceBuildItem item) { - services.produce(item); - LOGGER.debugf("Detected GrpcService associated with the '%s' configuration prefix", item.name); + // Only blocking and Mutiny stubs are supported + // The required type must have io.grpc.stub.AbstractBlockingStub or io.quarkus.grpc.runtime.MutinyStub in the hierarchy + // Note that we must use the computing index because the generated stubs are not part of the app index + Set rawTypes = getRawTypeClosure(index.getComputingIndex().getClassByName(injectionType.name()), + index.getComputingIndex()); + + if (rawTypes.contains(GrpcDotNames.ABSTRACT_BLOCKING_STUB)) { + item.addStub(injectionType.name(), StubType.BLOCKING); + } else if (rawTypes.contains(GrpcDotNames.MUTINY_STUB)) { + item.addStub(injectionType.name(), StubType.MUTINY); + } else { + throw new DeploymentException( + injectionType + " cannot be injected into " + injectionPoint.getTargetInfo() + + " - only blocking stubs, reactive stubs based on Mutiny and io.grpc.Channel can be injected via @GrpcClient"); } - }); + } if (!items.isEmpty()) { + for (GrpcClientBuildItem item : items.values()) { + services.produce(item); + LOGGER.debugf("Detected GrpcService associated with the '%s' configuration prefix", item.getServiceName()); + } features.produce(new FeatureBuildItem(GRPC_CLIENT)); } } - private boolean isMutinyStub(DotName name) { - return name.local().startsWith("Mutiny") && name.local().endsWith("Stub"); + private static Set getRawTypeClosure(ClassInfo classInfo, IndexView index) { + Set types = new HashSet<>(); + types.add(classInfo.name()); + // Interfaces + for (DotName name : classInfo.interfaceNames()) { + ClassInfo interfaceClassInfo = index.getClassByName(name); + if (interfaceClassInfo != null) { + types.addAll(getRawTypeClosure(interfaceClassInfo, index)); + } else { + // Interface not found in the index + types.add(name); + } + } + // Superclass + DotName superName = classInfo.superName(); + if (superName != null && !DotNames.OBJECT.equals(superName)) { + ClassInfo superClassInfo = index.getClassByName(superName); + if (superClassInfo != null) { + types.addAll(getRawTypeClosure(superClassInfo, index)); + } else { + // Superclass not found in the index + types.add(superName); + } + } + return types; } @BuildStep - public void generateGrpcServicesProducers(List services, - BeanRegistrationPhaseBuildItem phase, - BuildProducer beans) { + public void generateGrpcServicesProducers(List services, + BuildProducer syntheticBeans) { - for (GrpcServiceBuildItem svc : services) { - // We generate 3 producers: + for (GrpcClientBuildItem svc : services) { + // We generate 3 synthetic beans: // 1. the channel // 2. the blocking stub - if blocking stub is set // 3. the mutiny stub - if mutiny stub is set @@ -157,9 +197,7 @@ public void generateGrpcServicesProducers(List services, // IMPORTANT: the channel producer relies on the io.quarkus.grpc.runtime.supports.GrpcClientConfigProvider // bean that provides the GrpcClientConfiguration for the specific service. - BeanConfigurator channelProducer = phase.getContext() - .configure(GrpcDotNames.CHANNEL) - .types(Channel.class) + syntheticBeans.produce(SyntheticBeanBuildItem.configure(GrpcDotNames.CHANNEL) .addQualifier().annotation(GrpcDotNames.GRPC_CLIENT).addValue("value", svc.getServiceName()).done() .scope(Singleton.class) .unremovable() @@ -169,27 +207,19 @@ public void accept(MethodCreator mc) { GrpcClientProcessor.this.generateChannelProducer(mc, svc); } }) - .destroyer(Channels.ChannelDestroyer.class); - channelProducer.done(); - beans.produce(new BeanRegistrationPhaseBuildItem.BeanConfiguratorBuildItem(channelProducer)); + .destroyer(Channels.ChannelDestroyer.class).done()); String svcName = svc.getServiceName(); - for (ClassType stubClass : svc.getStubClasses()) { - DotName stubClassName = stubClass.name(); - BeanConfigurator stubProducer = phase.getContext() - .configure(stubClassName) - .types(stubClass) + for (StubInfo stub : svc.getStubs()) { + syntheticBeans.produce(SyntheticBeanBuildItem.configure(stub.className) .addQualifier().annotation(GrpcDotNames.GRPC_CLIENT).addValue("value", svcName).done() .scope(Singleton.class) .creator(new Consumer() { @Override public void accept(MethodCreator mc) { - GrpcClientProcessor.this.generateStubProducer(mc, svcName, stubClassName, - isMutinyStub(stubClassName)); + GrpcClientProcessor.this.generateStubProducer(mc, svcName, stub); } - }); - stubProducer.done(); - beans.produce(new BeanRegistrationPhaseBuildItem.BeanConfiguratorBuildItem(stubProducer)); + }).done()); } } } @@ -206,29 +236,21 @@ void runtimeInitialize(BuildProducer producer) producer.produce(new RuntimeInitializedClassBuildItem("io.grpc.internal.RetriableStream")); } - private void generateChannelProducer(MethodCreator mc, GrpcServiceBuildItem svc) { + private void generateChannelProducer(MethodCreator mc, GrpcClientBuildItem svc) { ResultHandle name = mc.load(svc.getServiceName()); ResultHandle result = mc.invokeStaticMethod(CREATE_CHANNEL_METHOD, name); mc.returnValue(result); mc.close(); } - private void generateStubProducer(MethodCreator mc, String svcName, DotName stubClassName, boolean mutiny) { + private void generateStubProducer(MethodCreator mc, String svcName, StubInfo stubInfo) { ResultHandle prefix = mc.load(svcName); ResultHandle channel = mc.invokeStaticMethod(RETRIEVE_CHANNEL_METHOD, prefix); - MethodDescriptor descriptor; - if (mutiny) { - descriptor = MethodDescriptor - .ofMethod(convertToServiceName(stubClassName), "newMutinyStub", - stubClassName.toString(), - Channel.class.getName()); - } else { - descriptor = MethodDescriptor - .ofMethod(convertToServiceName(stubClassName), "newBlockingStub", - stubClassName.toString(), - Channel.class.getName()); - } + MethodDescriptor descriptor = MethodDescriptor + .ofMethod(convertToServiceName(stubInfo.className), stubInfo.type.getFactoryMethodName(), + stubInfo.className.toString(), + Channel.class.getName()); ResultHandle stub = mc.invokeStaticMethod(descriptor, channel); mc.returnValue(stub); diff --git a/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcDotNames.java b/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcDotNames.java index d951df524c3e3..4d8402c3d3cea 100644 --- a/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcDotNames.java +++ b/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcDotNames.java @@ -4,9 +4,11 @@ import io.grpc.BindableService; import io.grpc.Channel; +import io.grpc.stub.AbstractBlockingStub; import io.quarkus.gizmo.MethodDescriptor; import io.quarkus.grpc.GrpcClient; import io.quarkus.grpc.GrpcService; +import io.quarkus.grpc.runtime.MutinyStub; import io.quarkus.grpc.runtime.supports.Channels; import io.smallrye.common.annotation.Blocking; @@ -19,6 +21,9 @@ public class GrpcDotNames { static final DotName BLOCKING = DotName.createSimple(Blocking.class.getName()); + static final DotName ABSTRACT_BLOCKING_STUB = DotName.createSimple(AbstractBlockingStub.class.getName()); + static final DotName MUTINY_STUB = DotName.createSimple(MutinyStub.class.getName()); + static final MethodDescriptor CREATE_CHANNEL_METHOD = MethodDescriptor.ofMethod(Channels.class, "createChannel", Channel.class, String.class); static final MethodDescriptor RETRIEVE_CHANNEL_METHOD = MethodDescriptor.ofMethod(Channels.class, "retrieveChannel", diff --git a/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcServiceBuildItem.java b/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcServiceBuildItem.java deleted file mode 100644 index 3a13af76c03fe..0000000000000 --- a/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcServiceBuildItem.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.quarkus.grpc.deployment; - -import java.util.HashSet; -import java.util.Set; - -import org.jboss.jandex.ClassType; - -import io.quarkus.builder.item.MultiBuildItem; - -public final class GrpcServiceBuildItem extends MultiBuildItem { - - final String name; - Set stubClasses = new HashSet(); - - public GrpcServiceBuildItem(String name) { - this.name = name; - } - - public Set getStubClasses() { - return stubClasses; - } - - public void addStubClass(ClassType stubClass) { - stubClasses.add(stubClass); - } - - public String getServiceName() { - return name; - } -} diff --git a/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/client/InvalidInjectionTypeTest.java b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/client/InvalidInjectionTypeTest.java new file mode 100644 index 0000000000000..fcc798338f4eb --- /dev/null +++ b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/client/InvalidInjectionTypeTest.java @@ -0,0 +1,45 @@ +package io.quarkus.grpc.client; + +import static org.junit.jupiter.api.Assertions.fail; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.spi.DeploymentException; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.grpc.examples.helloworld.GreeterGrpc; +import io.grpc.examples.helloworld.HelloReply; +import io.grpc.examples.helloworld.HelloReplyOrBuilder; +import io.grpc.examples.helloworld.HelloRequest; +import io.grpc.examples.helloworld.HelloRequestOrBuilder; +import io.grpc.examples.helloworld.MutinyGreeterGrpc; +import io.quarkus.grpc.GrpcClient; +import io.quarkus.test.QuarkusUnitTest; + +public class InvalidInjectionTypeTest { + + @RegisterExtension + static QuarkusUnitTest runner = new QuarkusUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addClasses(GreeterGrpc.class, GreeterGrpc.GreeterStub.class, + MutinyGreeterGrpc.MutinyGreeterStub.class, MutinyGreeterGrpc.class, + HelloRequest.class, HelloReply.class, + HelloReplyOrBuilder.class, HelloRequestOrBuilder.class)) + .setExpectedException(DeploymentException.class); + + @Test + public void runTest() { + fail(); + } + + @ApplicationScoped + static class MyConsumer { + + @GrpcClient + GreeterGrpc.GreeterStub stub; + + } +} diff --git a/extensions/grpc/protoc/src/main/resources/MutinyStub.mustache b/extensions/grpc/protoc/src/main/resources/MutinyStub.mustache index b71dfc8fc1977..c9e50dd12982d 100644 --- a/extensions/grpc/protoc/src/main/resources/MutinyStub.mustache +++ b/extensions/grpc/protoc/src/main/resources/MutinyStub.mustache @@ -23,7 +23,7 @@ public final class {{className}} { } {{#javaDoc}}{{{javaDoc}}}{{/javaDoc}} - public static final class {{classPrefix}}{{serviceName}}Stub extends io.grpc.stub.AbstractStub<{{classPrefix}}{{serviceName}}Stub> { + public static final class {{classPrefix}}{{serviceName}}Stub extends io.grpc.stub.AbstractStub<{{classPrefix}}{{serviceName}}Stub> implements io.quarkus.grpc.runtime.MutinyStub { private {{serviceName}}Grpc.{{serviceName}}Stub delegateStub; private {{classPrefix}}{{serviceName}}Stub(io.grpc.Channel channel) { diff --git a/extensions/grpc/stubs/src/main/java/io/quarkus/grpc/runtime/MutinyStub.java b/extensions/grpc/stubs/src/main/java/io/quarkus/grpc/runtime/MutinyStub.java new file mode 100644 index 0000000000000..46f312d2e9a68 --- /dev/null +++ b/extensions/grpc/stubs/src/main/java/io/quarkus/grpc/runtime/MutinyStub.java @@ -0,0 +1,8 @@ +package io.quarkus.grpc.runtime; + +/** + * A marker interface that represents a generated Mutiny gRPC stub. + */ +public interface MutinyStub { + +} From b9ae73484ed85695914aa1614e6b43a2e7d2fd6b Mon Sep 17 00:00:00 2001 From: NetoDevel Date: Mon, 10 May 2021 20:49:57 -0300 Subject: [PATCH 0030/2077] Add information about DevServices in Redis documentation --- docs/src/main/asciidoc/redis.adoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/src/main/asciidoc/redis.adoc b/docs/src/main/asciidoc/redis.adoc index 72d4d86af73ce..a03ee0dc8707e 100644 --- a/docs/src/main/asciidoc/redis.adoc +++ b/docs/src/main/asciidoc/redis.adoc @@ -592,6 +592,9 @@ Quarkus supports a feature called DevServices that allows you to create various What that means practically, is that if you have docker running and have not configured `quarkus.redis.hosts`, Quarkus will automatically start a Redis container when running tests or dev-mode, and automatically configure the connection. +Available properties to customize the Redis DevService. +include::{generated-dir}/config/quarkus-redis-client-config-group-dev-services-config.adoc[opts=optional, leveloffset=+1] + When running the production version of the application, the Redis connection need to be configured as normal, so if you want to include a production database config in your `application.properties` and continue to use DevServices we recommend that you use the `%prod.` profile to define your Redis settings. From 4846729ae4b61a8020d57c7ddd323d6755ed9947 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 May 2021 21:08:08 +0000 Subject: [PATCH 0031/2077] Bump awssdk.version from 2.16.60 to 2.16.61 Bumps `awssdk.version` from 2.16.60 to 2.16.61. Updates `software.amazon.awssdk:bom` from 2.16.60 to 2.16.61 - [Release notes](https://github.com/aws/aws-sdk-java-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-java-v2/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java-v2/compare/2.16.60...2.16.61) Updates `apache-client` from 2.16.60 to 2.16.61 Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index b80a9d3893a60..db352b530e0ed 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -151,7 +151,7 @@ 3.8.0 1.3.1 2.9.0 - 2.16.60 + 2.16.61 2.38.1 1.4.2 1.4.32 From 4616d660ab2ff4fd5c1551fd140ae3e98ebda2fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 May 2021 21:21:40 +0000 Subject: [PATCH 0032/2077] Bump mysql-connector-java from 8.0.24 to 8.0.25 Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.24 to 8.0.25. - [Release notes](https://github.com/mysql/mysql-connector-j/releases) - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.24...8.0.25) Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index b80a9d3893a60..08506d2153b21 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -122,7 +122,7 @@ 1.4.197 42.2.20 2.7.2 - 8.0.24 + 8.0.25 7.2.2.jre8 21.1.0.0 10.14.2.0 From 7e618cb3673ad7362d2515e61e82ff9678b37734 Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Wed, 12 May 2021 10:14:16 +1000 Subject: [PATCH 0033/2077] Fix last modified and CL for memory resources --- .../classloading/MemoryClassPathElement.java | 17 ++++++++++++++ .../ClassLoadingResourceUrlTestCase.java | 22 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/classloading/MemoryClassPathElement.java b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/classloading/MemoryClassPathElement.java index 05db1d17360bd..cc875a8cb9600 100644 --- a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/classloading/MemoryClassPathElement.java +++ b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/classloading/MemoryClassPathElement.java @@ -18,6 +18,7 @@ public class MemoryClassPathElement extends AbstractClassPathElement { private volatile Map resources; + private volatile long lastModified = System.currentTimeMillis(); public MemoryClassPathElement(Map resources) { this.resources = resources; @@ -39,6 +40,7 @@ public void reset(Map resources) { } } this.resources = newResources; + lastModified = System.currentTimeMillis(); } @Override @@ -128,6 +130,21 @@ public void connect() throws IOException { public InputStream getInputStream() throws IOException { return new ByteArrayInputStream(resources.get(name)); } + + @Override + public long getLastModified() { + return lastModified; + } + + @Override + public int getContentLength() { + return resources.get(name).length; + } + + @Override + public long getContentLengthLong() { + return resources.get(name).length; + } }; } } diff --git a/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/classloader/ClassLoadingResourceUrlTestCase.java b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/classloader/ClassLoadingResourceUrlTestCase.java index 611d70bc06df7..b496f0d6c7f45 100644 --- a/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/classloader/ClassLoadingResourceUrlTestCase.java +++ b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/classloader/ClassLoadingResourceUrlTestCase.java @@ -2,12 +2,16 @@ import io.quarkus.bootstrap.classloading.DirectoryClassPathElement; import io.quarkus.bootstrap.classloading.JarClassPathElement; +import io.quarkus.bootstrap.classloading.MemoryClassPathElement; import io.quarkus.bootstrap.classloading.QuarkusClassLoader; import io.quarkus.bootstrap.util.IoUtils; import java.io.InputStream; import java.net.URL; +import java.net.URLConnection; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Collections; import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.asset.StringAsset; import org.jboss.shrinkwrap.api.exporter.ExplodedExporter; @@ -114,4 +118,22 @@ public void testUrlReturnedFromClassLoaderJarFile() throws Exception { IoUtils.recursiveDelete(path); } } + + @Test + public void testMemoryUrlConnections() throws Exception { + long start = System.currentTimeMillis(); + Thread.sleep(2); + + ClassLoader cl = QuarkusClassLoader.builder("test", getClass().getClassLoader(), false) + .addElement( + new MemoryClassPathElement(Collections.singletonMap("a.txt", "hello".getBytes(StandardCharsets.UTF_8)))) + .build(); + URL res = cl.getResource("a.txt"); + Assertions.assertNotNull(res); + URLConnection urlConnection = res.openConnection(); + Assertions.assertEquals(5, urlConnection.getContentLength()); + Assertions.assertTrue(urlConnection.getLastModified() > start); + Assertions.assertEquals("hello", new String(urlConnection.getInputStream().readAllBytes(), StandardCharsets.UTF_8)); + + } } From bed47a96e98f22564a9142d2bab76576a5a184bc Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Tue, 11 May 2021 14:39:34 +1000 Subject: [PATCH 0034/2077] Add initial continuous testing docs Also improve help output --- .../dev/RuntimeUpdatesProcessor.java | 6 +- .../dev/testing/TestConsoleHandler.java | 27 ++-- .../dev/testing/TestController.java | 23 +++ .../deployment/dev/testing/TestSupport.java | 20 +++ .../src/main/asciidoc/continuous-testing.adoc | 151 ++++++++++++++++++ .../asciidoc/getting-started-testing.adoc | 2 + 6 files changed, 218 insertions(+), 11 deletions(-) create mode 100644 docs/src/main/asciidoc/continuous-testing.adoc diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java index 7d2b8f22416ae..b594a6d79f514 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java @@ -403,7 +403,7 @@ public boolean doScan(boolean userInitiated, boolean force) throws IOException { } } - private Boolean instrumentationEnabled() { + public boolean instrumentationEnabled() { if (instrumentationEnabled != null) { return instrumentationEnabled; } @@ -906,6 +906,10 @@ public boolean toggleLiveReloadEnabled() { return liveReloadEnabled; } + public boolean isLiveReloadEnabled() { + return liveReloadEnabled; + } + static class TimestampSet { final Map watchedFileTimestamps = new ConcurrentHashMap<>(); final Map classFileChangeTimeStamps = new ConcurrentHashMap<>(); diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java index 51f906e7712d4..84e2198b789a4 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java @@ -39,6 +39,7 @@ public void handleInput(int[] keys) { if (disabled) { for (int i : keys) { if (i == 'r') { + promptHandler.setStatus("\u001B[33mStarting tests\u001b[0m"); TestSupport.instance().get().start(); } } @@ -88,16 +89,22 @@ public void listenerRegistered(TestController testController) { } public void printUsage() { - System.out.println("r - Re-run all tests"); - System.out.println("f - Re-run failed tests"); - System.out.println("b - Toggle 'broken only' mode, where only failing tests are run"); - System.out.println("v - Print failures from the last test run"); - System.out.println("o - Toggle test output"); - System.out.println("p - Pause tests"); - System.out.println("i - Toggle instrumentation based reload"); - System.out.println("l - Toggle live reload"); - System.out.println("s - Force live reload scan"); - System.out.println("h - Display this help"); + System.out.println("\nThe following commands are available:"); + System.out.println("[\u001b[32mr\u001b[0m] - Re-run all tests"); + System.out.println("[\u001b[32mf\u001b[0m] - Re-run failed tests"); + System.out.println("[\u001b[32mb\u001b[0m] - Toggle 'broken only' mode, where only failing tests are run (" + + (testController.isBrokenOnlyMode() ? "\u001b[32menabled\u001b[0m" : "\u001B[91mdisabled\u001b[0m") + ")"); + System.out.println("[\u001b[32mv\u001b[0m] - Print failures from the last test run"); + System.out.println("[\u001b[32mo\u001b[0m] - Toggle test output (" + + (testController.isDisplayTestOutput() ? "\u001b[32menabled\u001b[0m" : "\u001B[91mdisabled\u001b[0m") + ")"); + System.out.println("[\u001b[32mp\u001b[0m] - Pause tests"); + System.out.println("[\u001b[32mi\u001b[0m] - Toggle instrumentation based reload (" + + (testController.isInstrumentationEnabled() ? "\u001b[32menabled\u001b[0m" : "\u001B[91mdisabled\u001b[0m") + + ")"); + System.out.println("[\u001b[32ml\u001b[0m] - Toggle live reload (" + + (testController.isLiveReloadEnabled() ? "\u001b[32menabled\u001b[0m" : "\u001B[91mdisabled\u001b[0m") + ")"); + System.out.println("[\u001b[32ms\u001b[0m] - Force live reload scan"); + System.out.println("[\u001b[32mh\u001b[0m] - Display this help"); } diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestController.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestController.java index 30620c1a1777b..623acc95d2d1c 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestController.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestController.java @@ -50,4 +50,27 @@ public interface TestController { */ void printFullResults(); + /** + * + * @return true if broken only mode is enabled + */ + boolean isBrokenOnlyMode(); + + /** + * + * @return true if test output is enabled + */ + boolean isDisplayTestOutput(); + + /** + * + * @return true if live reload is enabled + */ + boolean isInstrumentationEnabled(); + + /** + * + * @return true if live reload is enabled + */ + boolean isLiveReloadEnabled(); } diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestSupport.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestSupport.java index 9e3cff05698a0..b12e5ec8ed083 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestSupport.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestSupport.java @@ -309,6 +309,26 @@ public void printFullResults() { } } + @Override + public boolean isBrokenOnlyMode() { + return failingTestsOnly; + } + + @Override + public boolean isDisplayTestOutput() { + return displayTestOutput; + } + + @Override + public boolean isInstrumentationEnabled() { + return RuntimeUpdatesProcessor.INSTANCE.instrumentationEnabled(); + } + + @Override + public boolean isLiveReloadEnabled() { + return RuntimeUpdatesProcessor.INSTANCE.isLiveReloadEnabled(); + } + public static class RunStatus { final long lastRun; diff --git a/docs/src/main/asciidoc/continuous-testing.adoc b/docs/src/main/asciidoc/continuous-testing.adoc new file mode 100644 index 0000000000000..5c2cc3551d915 --- /dev/null +++ b/docs/src/main/asciidoc/continuous-testing.adoc @@ -0,0 +1,151 @@ +//// +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 +//// += Quarkus - Continuous Testing + +include::./attributes.adoc[] + +:toc: macro +:toclevels: 4 +:doctype: book +:icons: font +:docinfo1: + +:numbered: +:sectnums: +:sectnumlevels: 4 + +Learn how to use continuous testing in your Quarkus Application. + +== Prerequisites + +To complete this guide, you need: + +* less than 15 minutes +* an IDE +* JDK 11+ installed with `JAVA_HOME` configured appropriately +* Apache Maven {maven-version} +* The completed greeter application from the link:getting-started[Getting Started Guide] + +== Introduction + +Quarkus supports continuous testing, where tests run immediately after code changes have been saved. This allows you to +get instant feedback on your code changes. Quarkus detects which tests cover which code, and uses this information to +only run the relevant tests when code is changed. + +== Solution + +Start the link:getting-started[Getting Started] application (or any other application) using `mvn quarkus:dev`. Quarkus +will start in development mode as normal, but down the bottom of the screen you should see the following: + +[source] +---- +-- +Tests paused, press [r] to resume +---- + +Press `r` and the tests will start running. You should see the status change down the bottom of the screen as they +are running, and it should finish with: + +[source] +---- +-- +Tests all passed, 2 tests were run, 0 were skipped. Tests took 1470ms. +Press [r] to re-run, [v] to view full results, [p] to pause, [h] for more options> +---- + + +NOTE: If you want continuous testing to start automatically you can set `quarkus.test.continuous-testing=enabled` in +`application.properties`. If you don't want it at all you can change this to `disabled`. + + +Now you can start making changes to your application. Go into the `GreetingResource` and change the hello endpoint to +return `"hello world"`, and save the file. Quarkus should immediately re-run the test, and you should get output similar +to the following: + +[source] +---- +2021-05-11 14:21:34,338 ERROR [io.qua.test] (Test runner thread) Test GreetingResourceTest#testHelloEndpoint() failed +: java.lang.AssertionError: 1 expectation failed. +Response body doesn't match expectation. +Expected: is "hello" + Actual: hello world + + at io.restassured.internal.ValidatableResponseImpl.body(ValidatableResponseImpl.groovy) + at org.acme.getting.started.GreetingResourceTest.testHelloEndpoint(GreetingResourceTest.java:21) + + +-- +Test run failed, 2 tests were run, 1 failed, 0 were skipped. Tests took 295ms +Press [r] to re-run, [v] to view full results, [p] to pause, [h] for more options> +---- + +Change it back and the tests will run again. + +== Controlling Continuous Testing + +There are various hotkeys you can use to control continuous testing. Pressing `h` will display the following list +of commands: + +[source] +---- +The following commands are available: +[r] - Re-run all tests +[f] - Re-run failed tests +[b] - Toggle 'broken only' mode, where only failing tests are run (disabled) +[v] - Print failures from the last test run +[o] - Toggle test output (disabled) +[p] - Pause tests +[i] - Toggle instrumentation based reload (disabled) +[l] - Toggle live reload (enabled) +[s] - Force live reload scan +[h] - Display this help +---- + +These are explained below: + +[r] - Re-run all tests:: +This will re-run every test + +[f] - Re-run failed tests:: +This will re-run every failing test + +[b] - Toggle 'broken only' mode, where only failing tests are run:: +Broken only mode will only run tests that have previously failed, even if other tests would normally be affected by a code +change. This can be useful if you are modifying code that is used by lots of tests, but you only want to focus on debugging +the failing one. + +[v] - Print failures from the last test run:: +Prints the failures to the console again, this can be useful if there has been lots of console output since the last run. + +[o] - Toggle test output:: +By default test output is filtered and not displayed on the console, so that test output and dev mode output is not +interleaved. Enabling test output will print output to the console when tests are run. Even when output is disabled +the filtered output is saved and can be viewed in the Dev UI. + +[p] - Pause tests:: +Temporarily stops running tests. This can be useful if you are making lots of changes, and don't want feedback until they +are all done. + +[i] - Toggle instrumentation based reload:: +This is not directly related to testing, but allows you to toggle instrumentation based reload. This will allow live reload +to avoid a restart if a change does not affect the structure of a class, which gives a faster reload and allows you to keep +state. + +[l] - Toggle live reload:: +This is not directly related to testing, but allows you to turn live reload on and off. + +[s] - Force live reload scan:: +This will force a scan for changed file, and will perform a live reload if anything has changed. This will still work even +if live reload is disabled. + + +=== Configuring Continuous Testing + +Continuous testing supports multiple configuration options that can be used to limit the tests that are run, and +to control the output. The configuration properties are shown below: + +include::{generated-dir}/config/quarkus-test.adoc[opts=optional, leveloffset=+2] + diff --git a/docs/src/main/asciidoc/getting-started-testing.adoc b/docs/src/main/asciidoc/getting-started-testing.adoc index 3263e7ccf7ead..9dca364914a59 100644 --- a/docs/src/main/asciidoc/getting-started-testing.adoc +++ b/docs/src/main/asciidoc/getting-started-testing.adoc @@ -40,6 +40,8 @@ To complete this guide, you need: In this guide, we expand on the initial test that was created as part of the Getting Started Guide. We cover injection into tests and also how to test native executables. +NOTE: Quarkus supports Continuous testing, but this is covered by the link:continuous-testing[Continuous Testing Guide]. + == Solution We recommend that you follow the instructions in the next sections and create the application step by step. From 4032ac89b5d960407ccd73e5c622ea84e843fef8 Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Wed, 12 May 2021 12:04:20 +1000 Subject: [PATCH 0035/2077] Fix wrong failure number Also add a divider to make it clear where test output begins and ends --- .../deployment/dev/testing/TestConsoleHandler.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java index 51f906e7712d4..df7866c597b0f 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java @@ -152,7 +152,11 @@ public void runComplete(TestRunResults results) { + " were skipped. Tests took " + (results.getTotalTime()) + "ms." + "\u001b[0m"; } else { - int failedTestsNum = results.getCurrentFailing().size(); + int failedTestsNum = results.getCurrentFailing().values().stream().mapToInt((s) -> s.getFailing().size()) + .sum(); + //TODO: this should not use the logger, it should print a nicer status + log.error( + "==================== \u001B[91m" + failedTestsNum + " TESTS FAILED\u001b[0m ===================="); boolean hasFailingTests = failedTestsNum > 0; for (Map.Entry classEntry : results.getCurrentFailing().entrySet()) { for (TestResult test : classEntry.getValue().getFailing()) { @@ -161,6 +165,8 @@ public void runComplete(TestRunResults results) { test.getTestExecutionResult().getThrowable().get()); } } + log.error( + "==================== \u001B[91mEND TEST REPORT\u001b[0m ===================="); String output = String.format("Test run failed, %d tests were run, ", methodCount.get()) + String.format("%s%d failed%s, ", hasFailingTests ? "\u001B[1m" : "", failedTestsNum, From f782b176f2094123c871162145a6f99a5ad0d23c Mon Sep 17 00:00:00 2001 From: Clement Escoffier Date: Wed, 12 May 2021 08:21:53 +0200 Subject: [PATCH 0036/2077] Fix the outdated distroless documentation --- .../main/asciidoc/building-native-image.adoc | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/docs/src/main/asciidoc/building-native-image.adoc b/docs/src/main/asciidoc/building-native-image.adoc index d8cb99b439e21..730fcf2c68d69 100644 --- a/docs/src/main/asciidoc/building-native-image.adoc +++ b/docs/src/main/asciidoc/building-native-image.adoc @@ -494,8 +494,6 @@ And finally, run it with: docker run -i --rm -p 8080:8080 quarkus-quickstart/getting-started ---- -NOTE: If you are interested in tiny Docker images, check the {quarkus-images-url}/main/distroless[distroless] version. - === Using a multi-stage Docker build The previous section showed you how to build a native executable using Maven or Gradle, but it requires you to have created the native executable first. @@ -600,6 +598,31 @@ Please see link:native-and-ssl#working-with-containers[our Using SSL With Native NOTE: To use Mandrel instead of GraalVM CE, update the `FROM` clause to: `FROM quay.io/quarkus/ubi-quarkus-mandrel:$TAG AS build`. `$TAG` can be found on the https://quay.io/repository/quarkus/ubi-quarkus-mandrel?tab=tags[Quarkus Mandrel Images Tags page]. +=== Using a distroless base image + +If you are looking for small container images, the https://github.com/GoogleContainerTools/distroless[distroless] approach reduces the size of the base layer. +The idea behind _distroless_ is the usage of a single and minimal base image containing all the requirements, and sometimes even the application itself. + +Quarkus provides a distroless base image that you can use in your `Dockerfile`. +You only need to copy your application, and you are done: + +[source, dockerfile] +---- +FROM quay.io/quarkus/quarkus-distroless-image:1.0 +COPY target/*-runner /application + +EXPOSE 8080 +USER nonroot + +CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] +---- + +TIP: Projects generated with https://code.quarkus.io already have this Dockerfile in the `src/main/docker` directory. + +Quarkus provides the `quay.io/quarkus/quarkus-distroless-image:1.0` image. +It contains the required packages to run a native executable and is only **9Mb**. +Just add your application on top of this image, and you will get a tiny container image. + == Debugging native executable Starting with Oracle GraalVM 20.2 or Mandrel 20.1, From 3e00851aee46851ba5540b7de957a65425a58071 Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Wed, 12 May 2021 14:44:52 +1000 Subject: [PATCH 0037/2077] Fix large blank space in stack traces A bug in AeshConsole can mess up console output when a large number of lines is written. --- .../deployment/dev/console/AeshConsole.java | 74 ++++++++++--------- .../dev/testing/TestConsoleHandler.java | 2 +- 2 files changed, 41 insertions(+), 35 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/console/AeshConsole.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/console/AeshConsole.java index c2fc47ef6e66e..e490f6fcd7631 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/console/AeshConsole.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/console/AeshConsole.java @@ -266,46 +266,52 @@ public void write(String s) { return; } } - clearStatusMessages(buffer); - int cursorPos = lastWriteCursorX; - gotoLine(buffer, size.getHeight()); - String stripped = stripAnsiCodes(s); - int lines = countLines(s, cursorPos); - int trailing = 0; - int index = stripped.lastIndexOf("\n"); - if (index == -1) { - trailing = stripped.length(); + if (totalStatusLines == 0) { + writeQueue.add(s); } else { - trailing = stripped.length() - index - 1; - } + clearStatusMessages(buffer); + int cursorPos = lastWriteCursorX; + gotoLine(buffer, size.getHeight()); + String stripped = stripAnsiCodes(s); + int lines = countLines(s, cursorPos); + int trailing = 0; + int index = stripped.lastIndexOf("\n"); + if (index == -1) { + trailing = stripped.length(); + } else { + trailing = stripped.length() - index - 1; + } - int newCursorPos; - if (lines == 0) { - newCursorPos = trailing + cursorPos; - } else { - newCursorPos = trailing; - } + int newCursorPos; + if (lines == 0) { + newCursorPos = trailing + cursorPos; + } else { + newCursorPos = trailing; + } - if (cursorPos > 1 && lines == 0) { + if (cursorPos > 1 && lines == 0) { + buffer.append(s); + lastWriteCursorX = newCursorPos; + //partial line, just write it + connection.write(buffer.toString()); + return; + } + if (lines == 0) { + lines++; + } + //move the existing content up by the number of lines + int appendLines = Math.max(Math.min(cursorPos > 1 ? lines - 1 : lines, totalStatusLines), 1); + clearStatusMessages(buffer); + buffer.append("\033[").append(size.getHeight() - totalStatusLines).append(";").append(0).append("H"); buffer.append(s); + buffer.append("\033[").append(size.getHeight()).append(";").append(0).append("H"); + for (int i = 0; i < appendLines; ++i) { + buffer.append("\n"); + } lastWriteCursorX = newCursorPos; - //partial line, just write it - connection.write(buffer.toString()); - return; - } - if (lines == 0) { - lines++; + printStatusAndPrompt(buffer); + writeQueue.add(buffer.toString()); } - //move the existing content up by the number of lines - int appendLines = cursorPos > 1 ? lines - 1 : lines; - for (int i = 0; i < appendLines; ++i) { - buffer.append("\n"); - } - buffer.append("\033[").append(size.getHeight() - totalStatusLines - lines).append(";").append(0).append("H"); - buffer.append(s); - lastWriteCursorX = newCursorPos; - printStatusAndPrompt(buffer); - writeQueue.add(buffer.toString()); } deadlockSafeWrite(); } diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java index 51f906e7712d4..54c6ca4c92800 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java @@ -84,7 +84,7 @@ public void promptHandler(InputHandler.ConsoleStatus promptHandler) { @Override public void listenerRegistered(TestController testController) { this.testController = testController; - promptHandler.setStatus(PAUSED_PROMPT); + promptHandler.setPrompt(PAUSED_PROMPT); } public void printUsage() { From a912e1d812415ac054bda8d78fdfb2acc1dd9a8f Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Wed, 12 May 2021 09:28:38 +0200 Subject: [PATCH 0038/2077] DevConsoleFilter - query string should not be stripped away - otherwise a dev ui handler may not access query params --- .../vertx/http/runtime/devmode/DevConsoleFilter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/devmode/DevConsoleFilter.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/devmode/DevConsoleFilter.java index df61117c23c01..4a870d1383fc1 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/devmode/DevConsoleFilter.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/devmode/DevConsoleFilter.java @@ -35,12 +35,12 @@ public void handle(RoutingContext event) { headers.put(entry.getKey(), event.request().headers().getAll(entry.getKey())); } if (event.getBody() != null) { - DevConsoleRequest request = new DevConsoleRequest(event.request().method().name(), event.request().path(), headers, + DevConsoleRequest request = new DevConsoleRequest(event.request().method().name(), event.request().uri(), headers, event.getBody().getBytes()); setupFuture(event, request.getResponse()); DevConsoleManager.sentRequest(request); } else if (event.request().isEnded()) { - DevConsoleRequest request = new DevConsoleRequest(event.request().method().name(), event.request().path(), headers, + DevConsoleRequest request = new DevConsoleRequest(event.request().method().name(), event.request().uri(), headers, new byte[0]); setupFuture(event, request.getResponse()); DevConsoleManager.sentRequest(request); @@ -48,7 +48,7 @@ public void handle(RoutingContext event) { event.request().bodyHandler(new Handler() { @Override public void handle(Buffer body) { - DevConsoleRequest request = new DevConsoleRequest(event.request().method().name(), event.request().path(), + DevConsoleRequest request = new DevConsoleRequest(event.request().method().name(), event.request().uri(), headers, body.getBytes()); setupFuture(event, request.getResponse()); DevConsoleManager.sentRequest(request); From a38ce98b8abccc3f64431e924e240a3e43562558 Mon Sep 17 00:00:00 2001 From: Julien Ponge Date: Wed, 12 May 2021 09:40:46 +0200 Subject: [PATCH 0039/2077] Remove the mutiny-vertx.version and smallrye-reactive-utils.version redundant properties --- bom/application/pom.xml | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 64e5bcdab3557..0e8749b1e1df1 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -140,7 +140,6 @@ 1.0.3 3.4.1.Final 0.17.0 - 2.3.0 2.8.0 3.5.7 @@ -4414,7 +4413,7 @@ io.smallrye.reactive smallrye-mutiny-vertx-core - ${mutiny-vertx.version} + ${smallrye-reactive-utils.version} com.fasterxml.jackson.core @@ -4429,27 +4428,27 @@ io.smallrye.reactive smallrye-mutiny-vertx-web-client - ${mutiny-vertx.version} + ${smallrye-reactive-utils.version} io.smallrye.reactive smallrye-mutiny-vertx-sql-client - ${mutiny-vertx.version} + ${smallrye-reactive-utils.version} io.smallrye.reactive smallrye-mutiny-vertx-db2-client - ${mutiny-vertx.version} + ${smallrye-reactive-utils.version} io.smallrye.reactive smallrye-mutiny-vertx-mysql-client - ${mutiny-vertx.version} + ${smallrye-reactive-utils.version} io.smallrye.reactive smallrye-mutiny-vertx-pg-client - ${mutiny-vertx.version} + ${smallrye-reactive-utils.version} @@ -4460,12 +4459,12 @@ io.smallrye.reactive smallrye-mutiny-vertx-mail-client - ${mutiny-vertx.version} + ${smallrye-reactive-utils.version} io.smallrye.reactive smallrye-mutiny-vertx-redis-client - ${mutiny-vertx.version} + ${smallrye-reactive-utils.version} io.vertx @@ -4724,17 +4723,17 @@ io.smallrye.reactive smallrye-reactive-converter-api - ${mutiny-vertx.version} + ${smallrye-reactive-utils.version} io.smallrye.reactive smallrye-reactive-converter-mutiny - ${mutiny-vertx.version} + ${smallrye-reactive-utils.version} io.smallrye.reactive smallrye-reactive-converter-rxjava2 - ${mutiny-vertx.version} + ${smallrye-reactive-utils.version} From 741859a00ef2d7d5c26b356ae61f7bdb08fd71af Mon Sep 17 00:00:00 2001 From: Falko Modler Date: Wed, 12 May 2021 10:28:32 +0200 Subject: [PATCH 0040/2077] CI: Move pom.xml change detection to update*-dependencies.sh --- .github/workflows/ci-actions-incremental.yml | 34 ++----------------- .../gradle/update-dependencies.sh | 12 ++++++- tcks/resteasy-reactive/pom.xml | 1 + tcks/resteasy-reactive/update-dependencies.sh | 13 ++++++- update-extension-dependencies.sh | 12 ++++++- 5 files changed, 38 insertions(+), 34 deletions(-) diff --git a/.github/workflows/ci-actions-incremental.yml b/.github/workflows/ci-actions-incremental.yml index b2fbc82f8be68..0db07e6013476 100644 --- a/.github/workflows/ci-actions-incremental.yml +++ b/.github/workflows/ci-actions-incremental.yml @@ -127,16 +127,7 @@ jobs: ./mvnw -T1C $COMMON_MAVEN_ARGS -DskipTests -DskipITs -Dinvoker.skip -Dno-format -Dtcks clean install - name: Verify extension dependencies shell: bash - run: | - ./update-extension-dependencies.sh $COMMON_MAVEN_ARGS - if [ `git status -s -u no '*pom.xml' | wc -l` -ne 0 ] - then - echo -e '\033[0;31mError:\033[0m Dependencies to extension artifacts are outdated!' 1>&2 - echo -e '\033[0;31mError:\033[0m Run ./update-extension-dependencies.sh and add the modified pom.xml files to your commit.' 1>&2 - echo -e '\033[0;31mError:\033[0m Diff is:' 1>&2 - git --no-pager diff '*pom.xml' 1>&2 - exit 1 - fi + run: ./update-extension-dependencies.sh $COMMON_MAVEN_ARGS - name: Get GIB arguments id: get-gib-args env: @@ -499,16 +490,7 @@ jobs: # runs on Windows as well but would require newline conversion, not worth it if: matrix.os.family == 'Linux' shell: bash - run: | - ./integration-tests/gradle/update-dependencies.sh $COMMON_MAVEN_ARGS - if [ `git status -s -u no '*pom.xml' | wc -l` -ne 0 ] - then - echo -e '\033[0;31mError:\033[0m Dependencies in integration-tests/gradle/pom.xml are outdated!' 1>&2 - echo -e '\033[0;31mError:\033[0m Run update-dependencies.sh in integration-tests/gradle and add the modified pom.xml file to your commit.' 1>&2 - echo -e '\033[0;31mError:\033[0m Diff is:' 1>&2 - git --no-pager diff '*pom.xml' 1>&2 - exit 1 - fi + run: ./integration-tests/gradle/update-dependencies.sh $COMMON_MAVEN_ARGS - name: Build shell: bash # Important: keep -pl ... in sync with "Calculate run flags"! @@ -655,17 +637,7 @@ jobs: - name: Verify resteasy-reative dependencies # note: ideally, this would be run _before_ mvnw but that would required building tcks/resteasy-reactive in two steps shell: bash - run: | - ./tcks/resteasy-reactive/update-dependencies.sh $COMMON_MAVEN_ARGS - if [ `git status -s -u no '*pom.xml' | wc -l` -ne 0 ] - then - echo -e '\033[0;31mError:\033[0m Dependencies in tcks/resteasy-reactive/pom.xml are outdated!' 1>&2 - echo -e '\033[0;31mError:\033[0m Run './mvnw clean process-test-resources -f tcks/resteasy-reactive && tcks/resteasy-reactive/update-dependencies.sh' \ - and add the modified pom.xml file to your commit.' 1>&2 - echo -e '\033[0;31mError:\033[0m Diff is:' 1>&2 - git --no-pager diff '*pom.xml' 1>&2 - exit 1 - fi + run: ./tcks/resteasy-reactive/update-dependencies.sh $COMMON_MAVEN_ARGS - name: Prepare failure archive (if maven failed) if: failure() shell: bash diff --git a/integration-tests/gradle/update-dependencies.sh b/integration-tests/gradle/update-dependencies.sh index da53e16420a08..612ca588300e5 100755 --- a/integration-tests/gradle/update-dependencies.sh +++ b/integration-tests/gradle/update-dependencies.sh @@ -84,4 +84,14 @@ echo '' echo 'Sanity check...' echo '' # sanity check; make sure nothing stupid was added like non-existing deps -mvn dependency:resolve validate -Dsilent -q -f "${PRG_PATH}" $* \ No newline at end of file +mvn dependency:resolve validate -Dsilent -q -f "${PRG_PATH}" $* + +# CI only: verify that no pom.xml was touched (if changes are found, committer forgot to run script or to add changes) +if [ "${CI:-}" == true ] && [ $(git status -s -u no '*pom.xml' | wc -l) -ne 0 ] +then + echo -e '\033[0;31mError:\033[0m Dependencies in integration-tests/gradle/pom.xml are outdated!' 1>&2 + echo -e '\033[0;31mError:\033[0m Run update-dependencies.sh in integration-tests/gradle and add the modified pom.xml file to your commit.' 1>&2 + echo -e '\033[0;31mError:\033[0m Diff is:' 1>&2 + git --no-pager diff '*pom.xml' 1>&2 + exit 1 +fi diff --git a/tcks/resteasy-reactive/pom.xml b/tcks/resteasy-reactive/pom.xml index 522115118b8de..4170137b30e7a 100644 --- a/tcks/resteasy-reactive/pom.xml +++ b/tcks/resteasy-reactive/pom.xml @@ -12,6 +12,7 @@ quarkus-tck-resteasy-reactive Quarkus - TCK - RestEasy Reactive + pom diff --git a/tcks/resteasy-reactive/update-dependencies.sh b/tcks/resteasy-reactive/update-dependencies.sh index 7830991c3ad27..c138d2bc5e8a1 100755 --- a/tcks/resteasy-reactive/update-dependencies.sh +++ b/tcks/resteasy-reactive/update-dependencies.sh @@ -90,4 +90,15 @@ echo '' echo 'Sanity check...' echo '' # sanity check; make sure nothing stupid was added like non-existing deps -mvn dependency:resolve validate -Dsilent -q -f "${PRG_PATH}" $* \ No newline at end of file +mvn dependency:resolve validate -Dsilent -q -f "${PRG_PATH}" $* + +# CI only: verify that no pom.xml was touched (if changes are found, committer forgot to run script or to add changes) +if [ "${CI:-}" == true ] && [ $(git status -s -u no '*pom.xml' | wc -l) -ne 0 ] +then + echo -e '\033[0;31mError:\033[0m Dependencies in tcks/resteasy-reactive/pom.xml are outdated!' 1>&2 + echo -e '\033[0;31mError:\033[0m Run "./mvnw clean process-test-resources -f tcks/resteasy-reactive && tcks/resteasy-reactive/update-dependencies.sh" \ + and add the modified pom.xml file to your commit.' 1>&2 + echo -e '\033[0;31mError:\033[0m Diff is:' 1>&2 + git --no-pager diff '*pom.xml' 1>&2 + exit 1 +fi diff --git a/update-extension-dependencies.sh b/update-extension-dependencies.sh index d69bf644c4f99..8b05825575637 100755 --- a/update-extension-dependencies.sh +++ b/update-extension-dependencies.sh @@ -101,4 +101,14 @@ echo '' echo 'Sanity check...' echo '' # sanity check; make sure nothing stupid was added like non-existing deps -mvn dependency:resolve validate -Dsilent -q -f "${PRG_PATH}" -pl devtools/bom-descriptor-json,docs $* \ No newline at end of file +mvn dependency:resolve validate -Dsilent -q -f "${PRG_PATH}" -pl devtools/bom-descriptor-json,docs $* + +# CI only: verify that no pom.xml was touched (if changes are found, committer forgot to run script or to add changes) +if [ "${CI:-}" == true ] && [ $(git status -s -u no '*pom.xml' | wc -l) -ne 0 ] +then + echo -e '\033[0;31mError:\033[0m Dependencies to extension artifacts are outdated!' 1>&2 + echo -e '\033[0;31mError:\033[0m Run ./update-extension-dependencies.sh and add the modified pom.xml files to your commit.' 1>&2 + echo -e '\033[0;31mError:\033[0m Diff is:' 1>&2 + git --no-pager diff '*pom.xml' 1>&2 + exit 1 +fi From f1b4a9ed62af3aa3778123a80c39097a7a8b88b3 Mon Sep 17 00:00:00 2001 From: Falko Modler Date: Wed, 12 May 2021 10:28:32 +0200 Subject: [PATCH 0041/2077] CI: Unified jvm-tests --- .github/workflows/ci-actions-incremental.yml | 84 +++++--------------- 1 file changed, 21 insertions(+), 63 deletions(-) diff --git a/.github/workflows/ci-actions-incremental.yml b/.github/workflows/ci-actions-incremental.yml index 0db07e6013476..b58f0f75b34f8 100644 --- a/.github/workflows/ci-actions-incremental.yml +++ b/.github/workflows/ci-actions-incremental.yml @@ -212,9 +212,9 @@ jobs: echo "::set-output name=run_maven::${run_maven}" echo "::set-output name=run_tcks::${run_tcks}" - linux-jvm-tests: + jvm-tests: name: JVM Tests - JDK ${{matrix.java.name}} - runs-on: ubuntu-latest + runs-on: ${{ matrix.java.os-name }} # Skip main in forks if: "github.repository == 'quarkusio/quarkus' || !endsWith(github.ref, '/main')" needs: build-jdk11 @@ -228,18 +228,28 @@ jobs: - { name: "11", java-version: 11, - maven_args: "", - maven_opts: "-Xmx2g -XX:MaxMetaspaceSize=1g" + maven_args: "$JVM_TEST_MAVEN_ARGS", + maven_opts: "-Xmx2g -XX:MaxMetaspaceSize=1g", + os-name: "ubuntu-latest" } - { name: "16", java-version: 16, - maven_args: "-pl '!devtools/gradle' -Dno-descriptor-tests", - maven_opts: "-Xmx2g -XX:MaxMetaspaceSize=1g --add-opens java.base/java.util=ALL-UNNAMED" + maven_args: "$JVM_TEST_MAVEN_ARGS -pl '!devtools/gradle' -Dno-descriptor-tests", + maven_opts: "-Xmx2g -XX:MaxMetaspaceSize=1g --add-opens java.base/java.util=ALL-UNNAMED", + os-name: "ubuntu-latest" + } + - { + name: "11 Windows", + java-version: 11, + maven_args: "-DskipDocs -Dformat.skip", + maven_opts: "-Xmx1500m -XX:MaxMetaspaceSize=1g", + os-name: "windows-latest" } steps: - name: Stop mysql + if: "!startsWith(matrix.java.os-name, 'windows')" shell: bash run: | ss -ln @@ -253,18 +263,19 @@ jobs: run: git remote add quarkusio https://github.com/quarkusio/quarkus.git - name: apt clean + if: "!startsWith(matrix.java.os-name, 'windows')" shell: bash run: sudo apt-get clean - name: Reclaim Disk Space + if: "!startsWith(matrix.java.os-name, 'windows')" run: .github/ci-prerequisites.sh - - name: Set up JDK ${{ matrix.java.name }} + - name: Set up JDK ${{ matrix.java.java-version }} # Uses sha for added security since tags can be updated uses: joschi/setup-jdk@e87a7cec853d2dd7066adf837fe12bf0f3d45e52 with: java-version: ${{ matrix.java.java-version }} - release: ${{ matrix.java.release }} - name: Download Maven Repo uses: actions/download-artifact@v1 @@ -276,7 +287,7 @@ jobs: run: tar -xzf maven-repo.tgz -C ~ - name: Build shell: bash - run: ./mvnw $COMMON_MAVEN_ARGS $JVM_TEST_MAVEN_ARGS install -Dsurefire.timeout=600 -pl !integration-tests/gradle -pl !integration-tests/maven -pl !integration-tests/devtools ${{ matrix.java.maven_args }} ${{ needs.build-jdk11.outputs.gib_args }} + run: ./mvnw $COMMON_MAVEN_ARGS install -Dsurefire.timeout=600 -pl !integration-tests/gradle -pl !integration-tests/maven -pl !integration-tests/devtools ${{ matrix.java.maven_args }} ${{ needs.build-jdk11.outputs.gib_args }} - name: Prepare failure archive (if maven failed) if: failure() shell: bash @@ -285,7 +296,7 @@ jobs: uses: actions/upload-artifact@v1 if: failure() with: - name: test-reports-linux-jvm${{matrix.java.name}} + name: test-reports-jvm${{matrix.java.name}} path: 'test-reports.tgz' - name: Upload Surefire reports (if build failed) uses: actions/upload-artifact@v2 @@ -295,59 +306,6 @@ jobs: path: "**/target/*-reports/TEST-*.xml" retention-days: 2 - windows-jdk11-jvm-tests: - name: JVM Tests - JDK 11 Windows - runs-on: windows-latest - # Skip main in forks - if: "github.repository == 'quarkusio/quarkus' || !endsWith(github.ref, '/main')" - needs: build-jdk11 - timeout-minutes: 180 - env: - MAVEN_OPTS: -Xmx1500m -XX:MaxMetaspaceSize=1g - - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - name: Add quarkusio remote - shell: bash - run: git remote add quarkusio https://github.com/quarkusio/quarkus.git - - name: Set up JDK 11 - # Uses sha for added security since tags can be updated - uses: joschi/setup-jdk@e87a7cec853d2dd7066adf837fe12bf0f3d45e52 - with: - java-version: 11 - - name: Download Maven Repo - uses: actions/download-artifact@v1 - with: - name: maven-repo - path: . - - name: Extract Maven Repo - shell: bash - run: tar -xzf maven-repo.tgz -C ~ - - name: Build - shell: bash - run: ./mvnw $COMMON_MAVEN_ARGS -DskipDocs -Dformat.skip -Dsurefire.timeout=600 -pl !integration-tests/gradle -pl !integration-tests/maven -pl !integration-tests/devtools install ${{ needs.build-jdk11.outputs.gib_args }} - - name: Prepare failure archive (if maven failed) - if: failure() - shell: bash - run: | - # Disambiguate windows find from cygwin find - /usr/bin/find . -name '*-reports' -type d -o -name '*.log' | tar -czf test-reports.tgz -T - - - name: Upload failure Archive (if maven failed) - uses: actions/upload-artifact@v1 - if: failure() - with: - name: test-reports-windows-jdk11-jvm - path: 'test-reports.tgz' - - name: Upload Surefire reports (if build failed) - uses: actions/upload-artifact@v2 - if: ${{ failure() || cancelled() }} - with: - name: "surefire-reports-JVM Tests - JDK 11 Windows" - path: "**/target/*-reports/TEST-*.xml" - retention-days: 2 - linux-jvm-maven-tests: name: Maven Tests - JDK ${{matrix.java.name}} runs-on: ubuntu-latest From d4cd724e959191097f661263d2c69f0ce5bb3f95 Mon Sep 17 00:00:00 2001 From: Falko Modler Date: Wed, 12 May 2021 10:28:32 +0200 Subject: [PATCH 0042/2077] CI: Unified maven-tests --- .github/workflows/ci-actions-incremental.yml | 64 ++++---------------- 1 file changed, 11 insertions(+), 53 deletions(-) diff --git a/.github/workflows/ci-actions-incremental.yml b/.github/workflows/ci-actions-incremental.yml index b58f0f75b34f8..4668ebda80669 100644 --- a/.github/workflows/ci-actions-incremental.yml +++ b/.github/workflows/ci-actions-incremental.yml @@ -306,9 +306,9 @@ jobs: path: "**/target/*-reports/TEST-*.xml" retention-days: 2 - linux-jvm-maven-tests: + maven-tests: name: Maven Tests - JDK ${{matrix.java.name}} - runs-on: ubuntu-latest + runs-on: ${{ matrix.java.os-name }} needs: calculate-test-jobs env: MAVEN_OPTS: -Xmx2g -XX:MaxMetaspaceSize=1g @@ -321,7 +321,13 @@ jobs: java: - { name: "11", - java-version: 11 + java-version: 11, + os-name: "ubuntu-latest" + } + - { + name: "11 Windows", + java-version: 11, + os-name: "windows-latest" } steps: - uses: actions/checkout@v2 @@ -333,7 +339,7 @@ jobs: - name: Extract Maven Repo shell: bash run: tar -xzf maven-repo.tgz -C ~ - - name: Set up JDK ${{ matrix.java.name }} + - name: Set up JDK ${{ matrix.java.java-version }} # Uses sha for added security since tags can be updated uses: joschi/setup-jdk@e87a7cec853d2dd7066adf837fe12bf0f3d45e52 with: @@ -349,7 +355,7 @@ jobs: uses: actions/upload-artifact@v1 if: failure() with: - name: test-reports-linux-maven-java${{matrix.java.name}} + name: test-reports-maven-java${{matrix.java.name}} path: 'test-reports.tgz' - name: Upload Surefire reports (if build failed) uses: actions/upload-artifact@v2 @@ -359,54 +365,6 @@ jobs: path: "**/target/*-reports/TEST-*.xml" retention-days: 2 - windows-jdk11-jvm-maven-tests: - name: Maven Tests - JDK 11 Windows - runs-on: windows-latest - needs: calculate-test-jobs - env: - MAVEN_OPTS: -Xmx2g -XX:MaxMetaspaceSize=1g - # Skip main in forks - if: "needs.calculate-test-jobs.outputs.run_maven == 'true' && (github.repository == 'quarkusio/quarkus' || !endsWith(github.ref, '/main'))" - timeout-minutes: 60 - strategy: - fail-fast: false - steps: - - uses: actions/checkout@v2 - - name: Download Maven Repo - uses: actions/download-artifact@v1 - with: - name: maven-repo - path: . - - name: Extract Maven Repo - shell: bash - run: tar -xzf maven-repo.tgz -C ~ - - name: Set up JDK 11 - # Uses sha for added security since tags can be updated - uses: joschi/setup-jdk@e87a7cec853d2dd7066adf837fe12bf0f3d45e52 - with: - java-version: 11 - - name: Build - shell: bash - # Important: keep -pl ... in sync with "Calculate run flags"! - run: ./mvnw $COMMON_MAVEN_ARGS $JVM_TEST_MAVEN_ARGS install -pl 'integration-tests/maven' - - name: Prepare failure archive (if maven failed) - if: failure() - shell: bash - run: find . -name '*-reports' -type d -o -name '*.log' | tar -czf test-reports.tgz -T - - - name: Upload failure Archive (if maven failed) - uses: actions/upload-artifact@v1 - if: failure() - with: - name: test-reports-windows-maven-java11 - path: 'test-reports.tgz' - - name: Upload Surefire reports (if build failed) - uses: actions/upload-artifact@v2 - if: ${{ failure() || cancelled() }} - with: - name: "surefire-reports-Maven Tests - JDK 11 Windows" - path: "**/target/*-reports/TEST-*.xml" - retention-days: 2 - gradle-tests-jdk11-jvm: name: Gradle Tests - JDK 11 ${{matrix.os.family}} runs-on: ${{matrix.os.name}} From 7206e1bdd0c5590b281e39c74c1f50bbe583b20e Mon Sep 17 00:00:00 2001 From: Falko Modler Date: Wed, 12 May 2021 10:28:32 +0200 Subject: [PATCH 0043/2077] CI: Adjust gradle-tests to other matrix jobs --- .github/workflows/ci-actions-incremental.yml | 26 +++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci-actions-incremental.yml b/.github/workflows/ci-actions-incremental.yml index 4668ebda80669..d14de640e094e 100644 --- a/.github/workflows/ci-actions-incremental.yml +++ b/.github/workflows/ci-actions-incremental.yml @@ -365,9 +365,9 @@ jobs: path: "**/target/*-reports/TEST-*.xml" retention-days: 2 - gradle-tests-jdk11-jvm: - name: Gradle Tests - JDK 11 ${{matrix.os.family}} - runs-on: ${{matrix.os.name}} + gradle-tests: + name: Gradle Tests - JDK ${{matrix.java.name}} + runs-on: ${{matrix.java.os-name}} needs: calculate-test-jobs env: # leave more space for the actual gradle execution (which is just wrapped by maven) @@ -378,14 +378,16 @@ jobs: strategy: fail-fast: false matrix: - os: + java: - { - name: "ubuntu-latest", - family: "Linux" + name: "11", + java-version: 11, + os-name: "ubuntu-latest" } - { - name: "windows-latest", - family: "Windows" + name: "11 Windows", + java-version: 11, + os-name: "windows-latest" } steps: - uses: actions/checkout@v2 @@ -397,14 +399,14 @@ jobs: - name: Extract Maven Repo shell: bash run: tar -xzf maven-repo.tgz -C ~ - - name: Set up JDK 11 + - name: Set up JDK ${{ matrix.java.java-version }} # Uses sha for added security since tags can be updated uses: joschi/setup-jdk@e87a7cec853d2dd7066adf837fe12bf0f3d45e52 with: - java-version: 11 + java-version: ${{ matrix.java.java-version }} - name: Verify dependencies # runs on Windows as well but would require newline conversion, not worth it - if: matrix.os.family == 'Linux' + if: "!startsWith(matrix.java.os-name, 'windows')" shell: bash run: ./integration-tests/gradle/update-dependencies.sh $COMMON_MAVEN_ARGS - name: Build @@ -415,7 +417,7 @@ jobs: uses: actions/upload-artifact@v2 if: ${{ failure() || cancelled() }} with: - name: "surefire-reports-Gradle Tests - JDK 11 ${{matrix.os.family}}" + name: "surefire-reports-Gradle Tests - JDK ${{matrix.java.name}}" path: "**/build/test-results/test/TEST-*.xml" retention-days: 2 From 4b51d7fd238abf524faacab65b84e4184acc58c9 Mon Sep 17 00:00:00 2001 From: Falko Modler Date: Wed, 12 May 2021 10:28:33 +0200 Subject: [PATCH 0044/2077] CI: Unified devtools-tests --- .github/workflows/ci-actions-incremental.yml | 62 ++++---------------- 1 file changed, 11 insertions(+), 51 deletions(-) diff --git a/.github/workflows/ci-actions-incremental.yml b/.github/workflows/ci-actions-incremental.yml index d14de640e094e..33ee9ea309657 100644 --- a/.github/workflows/ci-actions-incremental.yml +++ b/.github/workflows/ci-actions-incremental.yml @@ -421,9 +421,9 @@ jobs: path: "**/build/test-results/test/TEST-*.xml" retention-days: 2 - linux-jvm-devtools-tests: + devtools-tests: name: Devtools Tests - JDK ${{matrix.java.name}} - runs-on: ubuntu-latest + runs-on: ${{matrix.java.os-name}} needs: calculate-test-jobs # Skip main in forks if: "needs.calculate-test-jobs.outputs.run_devtools == 'true' && (github.repository == 'quarkusio/quarkus' || !endsWith(github.ref, '/main'))" @@ -434,7 +434,13 @@ jobs: java: - { name: "11", - java-version: 11 + java-version: 11, + os-name: "ubuntu-latest" + } + - { + name: "11 Windows", + java-version: 11, + os-name: "windows-latest" } steps: - uses: actions/checkout@v2 @@ -446,7 +452,7 @@ jobs: - name: Extract Maven Repo shell: bash run: tar -xzf maven-repo.tgz -C ~ - - name: Set up JDK ${{ matrix.java.name }} + - name: Set up JDK ${{ matrix.java.java-version }} # Uses sha for added security since tags can be updated uses: joschi/setup-jdk@e87a7cec853d2dd7066adf837fe12bf0f3d45e52 with: @@ -462,7 +468,7 @@ jobs: uses: actions/upload-artifact@v1 if: failure() with: - name: test-reports-linux-devtools-java${{matrix.java.name}} + name: test-reports-devtools-java${{matrix.java.name}} path: 'test-reports.tgz' - name: Upload Surefire reports (if build failed) uses: actions/upload-artifact@v2 @@ -472,52 +478,6 @@ jobs: path: "**/target/*-reports/TEST-*.xml" retention-days: 2 - windows-jdk11-jvm-devtools-tests: - name: Devtools Tests - JDK 11 Windows - runs-on: windows-latest - needs: calculate-test-jobs - # Skip main in forks - if: "needs.calculate-test-jobs.outputs.run_devtools == 'true' && (github.repository == 'quarkusio/quarkus' || !endsWith(github.ref, '/main'))" - timeout-minutes: 60 - strategy: - fail-fast: false - steps: - - uses: actions/checkout@v2 - - name: Download Maven Repo - uses: actions/download-artifact@v1 - with: - name: maven-repo - path: . - - name: Extract Maven Repo - shell: bash - run: tar -xzf maven-repo.tgz -C ~ - - name: Set up JDK 11 - # Uses sha for added security since tags can be updated - uses: joschi/setup-jdk@e87a7cec853d2dd7066adf837fe12bf0f3d45e52 - with: - java-version: 11 - - name: Build - shell: bash - # Important: keep -pl ... in sync with "Calculate run flags"! - run: ./mvnw $COMMON_MAVEN_ARGS $JVM_TEST_MAVEN_ARGS install -pl 'integration-tests/devtools' - - name: Prepare failure archive (if maven failed) - if: failure() - shell: bash - run: find . -name '*-reports' -type d -o -name '*.log' | tar -czf test-reports.tgz -T - - - name: Upload failure Archive (if maven failed) - uses: actions/upload-artifact@v1 - if: failure() - with: - name: test-reports-windows-devtools-java11 - path: 'test-reports.tgz' - - name: Upload Surefire reports (if build failed) - uses: actions/upload-artifact@v2 - if: ${{ failure() || cancelled() }} - with: - name: "surefire-reports-Devtools Tests - JDK 11 Windows" - path: "**/target/*-reports/TEST-*.xml" - retention-days: 2 - tcks-test: name: MicroProfile TCKs Tests needs: [build-jdk11, calculate-test-jobs] From 7a091d72703f6b9552a0eca32b981e25dd4a5f85 Mon Sep 17 00:00:00 2001 From: Falko Modler Date: Wed, 12 May 2021 10:28:33 +0200 Subject: [PATCH 0045/2077] CI: run_jvm flag for jvm-tests, just like for the other test jobs --- .github/workflows/ci-actions-incremental.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-actions-incremental.yml b/.github/workflows/ci-actions-incremental.yml index 33ee9ea309657..9b20f65d172e8 100644 --- a/.github/workflows/ci-actions-incremental.yml +++ b/.github/workflows/ci-actions-incremental.yml @@ -181,6 +181,7 @@ jobs: GIB_IMPACTED_MODULES: ${{ needs.build-jdk11.outputs.gib_impacted }} outputs: native_matrix: ${{ steps.calc-native-matrix.outputs.matrix }} + run_jvm: ${{ steps.calc-run-flags.outputs.run_jvm }} run_devtools: ${{ steps.calc-run-flags.outputs.run_devtools }} run_gradle: ${{ steps.calc-run-flags.outputs.run_gradle }} run_maven: ${{ steps.calc-run-flags.outputs.run_maven }} @@ -197,16 +198,18 @@ jobs: - name: Calculate run flags id: calc-run-flags run: | - run_devtools=true; run_gradle=true; run_maven=true; run_tcks=true + run_jvm=true; run_devtools=true; run_gradle=true; run_maven=true; run_tcks=true if [ -n "${GIB_IMPACTED_MODULES}" ] then # Important: keep -pl ... in actual jobs in sync with the following grep commands! + if ! echo -n "${GIB_IMPACTED_MODULES}" | grep -qPv 'integration-tests/(devtools|gradle|maven)|tcks/.*'; then run_jvm=false; fi if ! echo -n "${GIB_IMPACTED_MODULES}" | grep -q 'integration-tests/devtools'; then run_devtools=false; fi if ! echo -n "${GIB_IMPACTED_MODULES}" | grep -q 'integration-tests/gradle'; then run_gradle=false; fi if ! echo -n "${GIB_IMPACTED_MODULES}" | grep -q 'integration-tests/maven'; then run_maven=false; fi if ! echo -n "${GIB_IMPACTED_MODULES}" | grep -q 'tcks/.*'; then run_tcks=false; fi fi - echo "run_devtools=${run_devtools}, run_gradle=${run_gradle}, run_maven=${run_maven}, run_tcks=${run_tcks}" + echo "run_jvm=${run_jvm}, run_devtools=${run_devtools}, run_gradle=${run_gradle}, run_maven=${run_maven}, run_tcks=${run_tcks}" + echo "::set-output name=run_jvm::${run_jvm}" echo "::set-output name=run_devtools::${run_devtools}" echo "::set-output name=run_gradle::${run_gradle}" echo "::set-output name=run_maven::${run_maven}" @@ -215,9 +218,9 @@ jobs: jvm-tests: name: JVM Tests - JDK ${{matrix.java.name}} runs-on: ${{ matrix.java.os-name }} + needs: [build-jdk11, calculate-test-jobs] # Skip main in forks - if: "github.repository == 'quarkusio/quarkus' || !endsWith(github.ref, '/main')" - needs: build-jdk11 + if: "needs.calculate-test-jobs.outputs.run_jvm == 'true' && (github.repository == 'quarkusio/quarkus' || !endsWith(github.ref, '/main'))" timeout-minutes: 240 env: MAVEN_OPTS: ${{ matrix.java.maven_opts }} @@ -287,6 +290,7 @@ jobs: run: tar -xzf maven-repo.tgz -C ~ - name: Build shell: bash + # Despite the pre-calculated run_jvm flag, GIB has to be re-run here to figure out the exact submodules to build. run: ./mvnw $COMMON_MAVEN_ARGS install -Dsurefire.timeout=600 -pl !integration-tests/gradle -pl !integration-tests/maven -pl !integration-tests/devtools ${{ matrix.java.maven_args }} ${{ needs.build-jdk11.outputs.gib_args }} - name: Prepare failure archive (if maven failed) if: failure() From 44af8bb9f5018ff7bba6dd641529ead2299a8a57 Mon Sep 17 00:00:00 2001 From: Falko Modler Date: Wed, 12 May 2021 10:28:33 +0200 Subject: [PATCH 0046/2077] Add direnv's .envrc to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8d820d866bdbb..11f1e911a836a 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,4 @@ nb-configuration.xml /lsp/ .jbang .sdkmanrc +.envrc From 47ea2ef18a6fddfdf69e10bd90171ae06d7475cf Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Wed, 12 May 2021 10:49:27 +0200 Subject: [PATCH 0047/2077] gRPC - specify client compression via GrpcClientConfiguration - resolves #17066 --- .../grpc/deployment/GrpcClientProcessor.java | 15 ++++-- .../quarkus/grpc/deployment/GrpcDotNames.java | 5 ++ .../grpc/client/ClientCompressionTest.java | 50 +++++++++++++++++++ .../hello-config-compression.properties | 4 ++ .../config/GrpcClientConfiguration.java | 6 +++ .../supports/GrpcClientConfigProvider.java | 16 ++++++ 6 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 extensions/grpc/deployment/src/test/java/io/quarkus/grpc/client/ClientCompressionTest.java create mode 100644 extensions/grpc/deployment/src/test/resources/hello-config-compression.properties diff --git a/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcClientProcessor.java b/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcClientProcessor.java index c347990f8f4d7..fa9407c2648b5 100644 --- a/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcClientProcessor.java +++ b/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcClientProcessor.java @@ -1,6 +1,7 @@ package io.quarkus.grpc.deployment; import static io.quarkus.deployment.Feature.GRPC_CLIENT; +import static io.quarkus.grpc.deployment.GrpcDotNames.CONFIGURE_STUB; import static io.quarkus.grpc.deployment.GrpcDotNames.CREATE_CHANNEL_METHOD; import static io.quarkus.grpc.deployment.GrpcDotNames.RETRIEVE_CHANNEL_METHOD; import static io.quarkus.grpc.deployment.ResourceRegistrationUtils.registerResourcesForProperties; @@ -244,15 +245,21 @@ private void generateChannelProducer(MethodCreator mc, GrpcClientBuildItem svc) } private void generateStubProducer(MethodCreator mc, String svcName, StubInfo stubInfo) { - ResultHandle prefix = mc.load(svcName); - ResultHandle channel = mc.invokeStaticMethod(RETRIEVE_CHANNEL_METHOD, prefix); + ResultHandle serviceName = mc.load(svcName); - MethodDescriptor descriptor = MethodDescriptor + // First obtain the channel instance for the given service name + ResultHandle channel = mc.invokeStaticMethod(RETRIEVE_CHANNEL_METHOD, serviceName); + + // Then create the stub, e.g. newBlockingStub(channel) + MethodDescriptor factoryMethod = MethodDescriptor .ofMethod(convertToServiceName(stubInfo.className), stubInfo.type.getFactoryMethodName(), stubInfo.className.toString(), Channel.class.getName()); + ResultHandle stub = mc.invokeStaticMethod(factoryMethod, channel); + + // If needed, modify the call options, e.g. stub = stub.withCompression("gzip") + stub = mc.invokeStaticMethod(CONFIGURE_STUB, serviceName, stub); - ResultHandle stub = mc.invokeStaticMethod(descriptor, channel); mc.returnValue(stub); mc.close(); } diff --git a/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcDotNames.java b/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcDotNames.java index 4d8402c3d3cea..c9935e6ddd109 100644 --- a/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcDotNames.java +++ b/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcDotNames.java @@ -5,11 +5,13 @@ import io.grpc.BindableService; import io.grpc.Channel; import io.grpc.stub.AbstractBlockingStub; +import io.grpc.stub.AbstractStub; import io.quarkus.gizmo.MethodDescriptor; import io.quarkus.grpc.GrpcClient; import io.quarkus.grpc.GrpcService; import io.quarkus.grpc.runtime.MutinyStub; import io.quarkus.grpc.runtime.supports.Channels; +import io.quarkus.grpc.runtime.supports.GrpcClientConfigProvider; import io.smallrye.common.annotation.Blocking; public class GrpcDotNames { @@ -29,4 +31,7 @@ public class GrpcDotNames { static final MethodDescriptor RETRIEVE_CHANNEL_METHOD = MethodDescriptor.ofMethod(Channels.class, "retrieveChannel", Channel.class, String.class); + static final MethodDescriptor CONFIGURE_STUB = MethodDescriptor.ofMethod(GrpcClientConfigProvider.class, + "configureStub", AbstractStub.class, String.class, AbstractStub.class); + } diff --git a/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/client/ClientCompressionTest.java b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/client/ClientCompressionTest.java new file mode 100644 index 0000000000000..83a00c51e26df --- /dev/null +++ b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/client/ClientCompressionTest.java @@ -0,0 +1,50 @@ +package io.quarkus.grpc.client; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.grpc.examples.helloworld.GreeterGrpc; +import io.grpc.examples.helloworld.HelloReply; +import io.grpc.examples.helloworld.HelloReplyOrBuilder; +import io.grpc.examples.helloworld.HelloRequest; +import io.grpc.examples.helloworld.HelloRequestOrBuilder; +import io.grpc.examples.helloworld.MutinyGreeterGrpc; +import io.quarkus.grpc.GrpcClient; +import io.quarkus.grpc.server.services.HelloService; +import io.quarkus.test.QuarkusUnitTest; + +public class ClientCompressionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest().setArchiveProducer( + () -> ShrinkWrap.create(JavaArchive.class) + .addClasses(MyConsumer.class, + MutinyGreeterGrpc.class, GreeterGrpc.class, + MutinyGreeterGrpc.MutinyGreeterStub.class, + HelloService.class, HelloRequest.class, HelloReply.class, + HelloReplyOrBuilder.class, HelloRequestOrBuilder.class)) + .withConfigurationResource("hello-config-compression.properties"); + + @Inject + MyConsumer consumer; + + @Test + public void testCallOptions() { + assertEquals("gzip", consumer.service.getCallOptions().getCompressor()); + } + + @Singleton + static class MyConsumer { + + @GrpcClient("hello-service") + MutinyGreeterGrpc.MutinyGreeterStub service; + + } +} diff --git a/extensions/grpc/deployment/src/test/resources/hello-config-compression.properties b/extensions/grpc/deployment/src/test/resources/hello-config-compression.properties new file mode 100644 index 0000000000000..74b529b53720e --- /dev/null +++ b/extensions/grpc/deployment/src/test/resources/hello-config-compression.properties @@ -0,0 +1,4 @@ +quarkus.grpc.clients.hello-service.host=localhost +quarkus.grpc.clients.hello-service.port=9001 +quarkus.grpc.clients.hello-service.keep-alive-timeout=1s +quarkus.grpc.clients.hello-service.compression=gzip \ No newline at end of file diff --git a/extensions/grpc/runtime/src/main/java/io/quarkus/grpc/runtime/config/GrpcClientConfiguration.java b/extensions/grpc/runtime/src/main/java/io/quarkus/grpc/runtime/config/GrpcClientConfiguration.java index 0d1f94c7f5eea..0a8c55abd07ee 100644 --- a/extensions/grpc/runtime/src/main/java/io/quarkus/grpc/runtime/config/GrpcClientConfiguration.java +++ b/extensions/grpc/runtime/src/main/java/io/quarkus/grpc/runtime/config/GrpcClientConfiguration.java @@ -143,4 +143,10 @@ public class GrpcClientConfiguration { */ @ConfigItem(defaultValue = "pick_first") public String loadBalancingPolicy; + + /** + * The compression to use for each call. The accepted values are {@code gzip} and {@code identity}. + */ + @ConfigItem + public Optional compression; } diff --git a/extensions/grpc/runtime/src/main/java/io/quarkus/grpc/runtime/supports/GrpcClientConfigProvider.java b/extensions/grpc/runtime/src/main/java/io/quarkus/grpc/runtime/supports/GrpcClientConfigProvider.java index ff4ddc78aafdf..daba88b8dfaec 100644 --- a/extensions/grpc/runtime/src/main/java/io/quarkus/grpc/runtime/supports/GrpcClientConfigProvider.java +++ b/extensions/grpc/runtime/src/main/java/io/quarkus/grpc/runtime/supports/GrpcClientConfigProvider.java @@ -5,6 +5,8 @@ import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; +import io.grpc.stub.AbstractStub; +import io.quarkus.arc.Arc; import io.quarkus.grpc.runtime.config.GrpcClientConfiguration; import io.quarkus.grpc.runtime.config.GrpcConfiguration; @@ -26,4 +28,18 @@ public GrpcClientConfiguration getConfiguration(String name) { } } + AbstractStub adjustCallOptions(String serviceName, AbstractStub stub) { + GrpcClientConfiguration clientConfig = config.clients != null ? config.clients.get(serviceName) : null; + if (clientConfig != null) { + if (clientConfig.compression.isPresent()) { + stub = stub.withCompression(clientConfig.compression.get()); + } + } + return stub; + } + + public static AbstractStub configureStub(String serviceName, AbstractStub stub) { + return Arc.container().instance(GrpcClientConfigProvider.class).get().adjustCallOptions(serviceName, stub); + } + } From 3f7dc74a0092b635557d7dd941b5380f2677e265 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Wed, 12 May 2021 15:06:15 +0300 Subject: [PATCH 0048/2077] Provide an actionable error message when byte[] is used as a field of the Multipart POJO This is done because users can easily assume that byte[] is supported when in reality it is not --- .../reactive/server/deployment/DotNames.java | 1 + .../MultipartPopulatorGenerator.java | 9 +++ .../ErroneousFieldMultipartInputTest.java | 59 +++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/multipart/ErroneousFieldMultipartInputTest.java diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/DotNames.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/DotNames.java index 8979dead825fd..0f5ec8db76d6f 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/DotNames.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/DotNames.java @@ -14,6 +14,7 @@ final class DotNames { static final String POPULATE_METHOD_NAME = "populate"; static final DotName OBJECT_NAME = DotName.createSimple(Object.class.getName()); static final DotName STRING_NAME = DotName.createSimple(String.class.getName()); + static final DotName BYTE_NAME = DotName.createSimple(byte.class.getName()); static final DotName INPUT_STREAM_NAME = DotName.createSimple(InputStream.class.getName()); static final DotName INPUT_STREAM_READER_NAME = DotName.createSimple(InputStreamReader.class.getName()); static final DotName FIELD_UPLOAD_NAME = DotName.createSimple(FileUpload.class.getName()); diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/MultipartPopulatorGenerator.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/MultipartPopulatorGenerator.java index 371f21f5c63f0..761300b55910b 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/MultipartPopulatorGenerator.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/MultipartPopulatorGenerator.java @@ -314,6 +314,15 @@ static String generate(ClassInfo multipartClassInfo, ClassOutput classOutput, In // this is a common enough mistake, so let's provide a good error message failIfFileTypeUsedAsGenericType(field, fieldType, fieldDotName); + if (fieldType.kind() == Type.Kind.ARRAY) { + if (fieldType.asArrayType().component().name().equals(DotNames.BYTE_NAME)) { + throw new IllegalArgumentException( + "'byte[]' cannot be used to read multipart file contents. Offending field is '" + + field.name() + "' of class '" + + field.declaringClass().name() + + "'. If you need to read the contents of the uploaded file, use 'Path' or 'File' as the field type and use File IO APIs to read the bytes, while making sure you annotate the endpoint with '@Blocking'"); + } + } if (fieldDotName.equals(DotNames.STRING_NAME) && partType.equals(MediaType.TEXT_PLAIN)) { // in this case all we need to do is read the value of the form attribute diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/multipart/ErroneousFieldMultipartInputTest.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/multipart/ErroneousFieldMultipartInputTest.java new file mode 100644 index 0000000000000..49c5f0a3343aa --- /dev/null +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/multipart/ErroneousFieldMultipartInputTest.java @@ -0,0 +1,59 @@ +package io.quarkus.resteasy.reactive.server.test.multipart; + +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.function.Supplier; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.jboss.resteasy.reactive.MultipartForm; +import org.jboss.resteasy.reactive.RestForm; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class ErroneousFieldMultipartInputTest { + + @RegisterExtension + static QuarkusUnitTest test = new QuarkusUnitTest() + .setArchiveProducer(new Supplier() { + @Override + public JavaArchive get() { + return ShrinkWrap.create(JavaArchive.class) + .addClasses(Input.class); + } + + }).setExpectedException(IllegalArgumentException.class); + + @Test + public void testSimple() { + fail("Should never be called"); + } + + @Path("test") + public static class TestEndpoint { + + @Produces(MediaType.TEXT_PLAIN) + @Consumes(MediaType.MULTIPART_FORM_DATA) + @POST + public int test(@MultipartForm Input formData) { + return formData.txtFile.length; + } + } + + public static class Input { + @RestForm + private String name; + + @RestForm + public byte[] txtFile; + } + +} From b861b7cb4122f87d3976ff1ab8d99769355179d7 Mon Sep 17 00:00:00 2001 From: xstefank Date: Wed, 5 May 2021 12:55:07 +0200 Subject: [PATCH 0049/2077] Upgrade SR Health to 3.0.2 --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index ca860c48dad8e..28de59bd3b55a 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -43,7 +43,7 @@ 1.2 1.6.0 2.2.0 - 3.0.1 + 3.0.2 3.0.1 2.1.4 1.1.0 From 4a2686dee7cc569fcb8e038946fcfe0457a17ee9 Mon Sep 17 00:00:00 2001 From: xstefank Date: Wed, 5 May 2021 12:55:40 +0200 Subject: [PATCH 0050/2077] Add security context propagation to the health check invocations --- docs/src/main/asciidoc/smallrye-health.adoc | 4 + .../deployment/SmallRyeHealthConfig.java | 6 ++ .../deployment/SmallRyeHealthProcessor.java | 9 ++ .../HealthCheckContextPropagationTest.java | 97 +++++++++++++++++++ .../runtime/SmallRyeHealthHandlerBase.java | 6 ++ 5 files changed, 122 insertions(+) create mode 100644 extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckContextPropagationTest.java diff --git a/docs/src/main/asciidoc/smallrye-health.adoc b/docs/src/main/asciidoc/smallrye-health.adoc index 78e58304f7288..3570fe0e4259c 100644 --- a/docs/src/main/asciidoc/smallrye-health.adoc +++ b/docs/src/main/asciidoc/smallrye-health.adoc @@ -320,6 +320,10 @@ error along with the health check response. } ---- +== Context propagation into the health check invocations + +For the perfomance reasons the context (e.g., CDI or security context) is not propagated into each health check invocation. However, if you need to enable this functionality you can set the config property `quarkus.smallrye-health.context-propagation=true` to allow the context propagation into every health check call. + == Extension health checks Some extension may provide default health checks, including the extension will automatically register its health checks. diff --git a/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthConfig.java b/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthConfig.java index 7cb60dfabf3fd..b63ebeef346c8 100644 --- a/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthConfig.java +++ b/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthConfig.java @@ -42,6 +42,12 @@ public class SmallRyeHealthConfig { @ConfigItem(defaultValue = "well") String wellnessPath; + /** + * Whether the context should be propagated to each health check invocation. + */ + @ConfigItem(defaultValue = "false") + boolean contextPropagation; + /** * SmallRye Health UI configuration */ diff --git a/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthProcessor.java b/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthProcessor.java index 81772eeeb8439..1466a4dccc0a8 100644 --- a/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthProcessor.java +++ b/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthProcessor.java @@ -51,6 +51,7 @@ import io.quarkus.deployment.builditem.LaunchModeBuildItem; import io.quarkus.deployment.builditem.LiveReloadBuildItem; import io.quarkus.deployment.builditem.ShutdownListenerBuildItem; +import io.quarkus.deployment.builditem.SystemPropertyBuildItem; import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem; import io.quarkus.deployment.configuration.ConfigurationError; import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem; @@ -267,6 +268,14 @@ public void defineHealthRoutes(BuildProducer routes, } + @BuildStep + public void translateSmallRyeConfigValues(SmallRyeHealthConfig healthConfig, + BuildProducer systemProperties) { + if (healthConfig.contextPropagation) { + systemProperties.produce(new SystemPropertyBuildItem("io.smallrye.health.context.propagation", "true")); + } + } + @BuildStep(onlyIf = OpenAPIIncluded.class) public void includeInOpenAPIEndpoint(BuildProducer openAPIProducer, NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem, diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckContextPropagationTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckContextPropagationTest.java new file mode 100644 index 0000000000000..0b514dac45afb --- /dev/null +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckContextPropagationTest.java @@ -0,0 +1,97 @@ +package io.quarkus.smallrye.health.test; + +import static io.restassured.RestAssured.when; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; + +import java.util.UUID; + +import javax.annotation.PostConstruct; +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; + +import org.eclipse.microprofile.health.HealthCheck; +import org.eclipse.microprofile.health.HealthCheckResponse; +import org.eclipse.microprofile.health.Liveness; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; +import io.restassured.parsing.Parser; + +public class HealthCheckContextPropagationTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.smallrye-health.context-propagation", "true") + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addClasses(RequestScopedBean.class, ContextualHC.class)); + + @Test + public void testContextPropagatedToHealthChecks() { + try { + RestAssured.defaultParser = Parser.JSON; + + String firstResponse = when().get("/q/health").then() + .body("status", is("UP"), + "checks.status", contains("UP"), + "checks.name", contains(ContextualHC.class.getName()), + "checks.data", is(notNullValue())) + .extract().response().jsonPath().getString("checks.data.request-scoped-instance"); + + String secondResponse = when().get("/q/health").then() + .extract().response().jsonPath().getString("checks.data.request-scoped-instance"); + + String thirdResponse = when().get("/q/health").then() + .extract().response().jsonPath().getString("checks.data.request-scoped-instance"); + + Assertions.assertNotEquals(firstResponse, secondResponse, getMessage("first", "second")); + Assertions.assertNotEquals(firstResponse, thirdResponse, getMessage("first", "third")); + Assertions.assertNotEquals(secondResponse, thirdResponse, getMessage("second", "third")); + } finally { + RestAssured.reset(); + } + } + + private String getMessage(String response1, String response2) { + return String.format("The CDI context should have been propagated to the health check invocations. " + + "However, %s and %s responses are the same", response1, response2); + } + + @RequestScoped + static class RequestScopedBean { + + String uuid; + + @PostConstruct + public void init() { + uuid = UUID.randomUUID().toString(); + } + + public String getUuid() { + return uuid; + } + } + + @Liveness + @ApplicationScoped + static class ContextualHC implements HealthCheck { + + @Inject + RequestScopedBean requestScopedBean; + + @Override + public HealthCheckResponse call() { + return HealthCheckResponse.named(ContextualHC.class.getName()).up() + .withData("request-scoped-instance", requestScopedBean.getUuid()) + .build(); + } + } + +} diff --git a/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/SmallRyeHealthHandlerBase.java b/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/SmallRyeHealthHandlerBase.java index 258560eb3d922..f1b41271c2ac7 100644 --- a/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/SmallRyeHealthHandlerBase.java +++ b/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/SmallRyeHealthHandlerBase.java @@ -6,6 +6,8 @@ import io.quarkus.arc.Arc; import io.quarkus.arc.ManagedContext; +import io.quarkus.security.identity.CurrentIdentityAssociation; +import io.quarkus.vertx.http.runtime.security.QuarkusHttpUser; import io.smallrye.health.SmallRyeHealth; import io.smallrye.health.SmallRyeHealthReporter; import io.vertx.core.Handler; @@ -34,6 +36,10 @@ public void handle(RoutingContext ctx) { } private void doHandle(RoutingContext ctx) { + QuarkusHttpUser user = (QuarkusHttpUser) ctx.user(); + if (user != null) { + Arc.container().instance(CurrentIdentityAssociation.class).get().setIdentity(user.getSecurityIdentity()); + } SmallRyeHealthReporter reporter = Arc.container().instance(SmallRyeHealthReporter.class).get(); SmallRyeHealth health = getHealth(reporter, ctx); HttpServerResponse resp = ctx.response(); From ae3b42613dc303d3e01f9f1663f0b91c3f1f2817 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Wed, 12 May 2021 15:04:12 +0200 Subject: [PATCH 0051/2077] Amazon S3 guide - Switch to new Mutiny transform() method --- docs/src/main/asciidoc/amazon-s3.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/main/asciidoc/amazon-s3.adoc b/docs/src/main/asciidoc/amazon-s3.adoc index f9fee85b475de..6511a05d3802b 100644 --- a/docs/src/main/asciidoc/amazon-s3.adoc +++ b/docs/src/main/asciidoc/amazon-s3.adoc @@ -511,7 +511,7 @@ public class S3AsyncClientResource extends CommonResource { return Uni.createFrom() .completionStage(() -> s3.getObject(buildGetRequest(objectKey), AsyncResponseTransformer.toFile(tempFile))) .onItem() - .apply(object -> Response.ok(tempFile) + .transform(object -> Response.ok(tempFile) .header("Content-Disposition", "attachment;filename=" + objectKey) .header("Content-Type", object.contentType()).build()); } From 92c601297cec28b04ea2e2cd681af77b2c60fe2d Mon Sep 17 00:00:00 2001 From: Ioannis Canellos Date: Wed, 12 May 2021 12:28:51 +0300 Subject: [PATCH 0052/2077] chore: bump to dekorate 2.1.4 --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index ca860c48dad8e..9ec53e73c42b1 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -155,7 +155,7 @@ 1.4.2 1.4.32 1.4.3 - 2.1.2 + 2.1.4 0.10.0 3.0.1 4.1.0 From c5e430c0425895adc97b85df0978617859b4998c Mon Sep 17 00:00:00 2001 From: NetoDevel Date: Mon, 10 May 2021 21:34:18 -0300 Subject: [PATCH 0053/2077] Adds Redis Devservices it --- integration-tests/pom.xml | 1 + integration-tests/redis-devservices/pom.xml | 91 +++++++++++++++++++ .../src/main/resources/application.properties | 5 + .../it/DevServicesRedisCustomPortITest.java | 22 +++++ .../it/DevServicesRedisDisabledITest.java | 22 +++++ .../devservices/it/DevServicesRedisITest.java | 42 +++++++++ .../it/profiles/DevServiceRedis.java | 14 +++ .../DevServicesCustomPortProfile.java | 19 ++++ .../profiles/DevServicesDisabledProfile.java | 19 ++++ .../redis/devservices/it/utils/SocketKit.java | 16 ++++ 10 files changed, 251 insertions(+) create mode 100644 integration-tests/redis-devservices/pom.xml create mode 100644 integration-tests/redis-devservices/src/main/resources/application.properties create mode 100644 integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/DevServicesRedisCustomPortITest.java create mode 100644 integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/DevServicesRedisDisabledITest.java create mode 100644 integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/DevServicesRedisITest.java create mode 100644 integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/profiles/DevServiceRedis.java create mode 100644 integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/profiles/DevServicesCustomPortProfile.java create mode 100644 integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/profiles/DevServicesDisabledProfile.java create mode 100644 integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/utils/SocketKit.java diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 09b417c0b01c3..e98fe39422ecd 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -173,6 +173,7 @@ native-config-profile logging-min-level-unset logging-min-level-set + redis-devservices grpc-tls diff --git a/integration-tests/redis-devservices/pom.xml b/integration-tests/redis-devservices/pom.xml new file mode 100644 index 0000000000000..011d7181492d1 --- /dev/null +++ b/integration-tests/redis-devservices/pom.xml @@ -0,0 +1,91 @@ + + + 4.0.0 + + io.quarkus + quarkus-integration-tests-parent + 999-SNAPSHOT + ../pom.xml + + quarkus-integration-test-redis-devservices + Quarkus - Integration Tests - Redis DevService + + + + io.quarkus + quarkus-redis-client + + + io.quarkus + quarkus-arc + + + io.quarkus + quarkus-junit5 + test + + + + io.quarkus + quarkus-redis-client-deployment + ${project.version} + pom + test + + + * + * + + + + + io.quarkus + quarkus-arc-deployment + ${project.version} + pom + test + + + * + * + + + + + + + + + src/main/resources + true + + + + + maven-surefire-plugin + + true + + + + maven-failsafe-plugin + + true + + + + io.quarkus + quarkus-maven-plugin + + + + build + + + + + + + + diff --git a/integration-tests/redis-devservices/src/main/resources/application.properties b/integration-tests/redis-devservices/src/main/resources/application.properties new file mode 100644 index 0000000000000..c7cf99c88db91 --- /dev/null +++ b/integration-tests/redis-devservices/src/main/resources/application.properties @@ -0,0 +1,5 @@ +#quarkus.redis.hosts=redis://localhost:6379 +quarkus.redis.health.enabled=true +#quarkus.redis.devservices.image-name=redis:6.0-alpine +#quarkus.redis.devservices.port=6377 +#quarkus.redis.devservices.enabled=true \ No newline at end of file diff --git a/integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/DevServicesRedisCustomPortITest.java b/integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/DevServicesRedisCustomPortITest.java new file mode 100644 index 0000000000000..004bc4430cfaf --- /dev/null +++ b/integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/DevServicesRedisCustomPortITest.java @@ -0,0 +1,22 @@ +package io.quarkus.redis.devservices.it; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import io.quarkus.redis.devservices.it.profiles.DevServicesCustomPortProfile; +import io.quarkus.redis.devservices.it.utils.SocketKit; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; + +@QuarkusTest +@TestProfile(DevServicesCustomPortProfile.class) +public class DevServicesRedisCustomPortITest { + + @Test + @DisplayName("should start redis container with the given custom port") + public void shouldStartRedisContainer() { + Assertions.assertTrue(SocketKit.isPortAlreadyUsed(6371)); + } + +} diff --git a/integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/DevServicesRedisDisabledITest.java b/integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/DevServicesRedisDisabledITest.java new file mode 100644 index 0000000000000..2d3d741595736 --- /dev/null +++ b/integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/DevServicesRedisDisabledITest.java @@ -0,0 +1,22 @@ +package io.quarkus.redis.devservices.it; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import io.quarkus.redis.devservices.it.profiles.DevServicesDisabledProfile; +import io.quarkus.redis.devservices.it.utils.SocketKit; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; + +@QuarkusTest +@TestProfile(DevServicesDisabledProfile.class) +public class DevServicesRedisDisabledITest { + + @Test + @DisplayName("should not start the redis container when devservices is disabled") + public void shouldStartRedisContainer() { + Assertions.assertFalse(SocketKit.isPortAlreadyUsed(6379)); + } + +} diff --git a/integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/DevServicesRedisITest.java b/integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/DevServicesRedisITest.java new file mode 100644 index 0000000000000..2d88d683e9f79 --- /dev/null +++ b/integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/DevServicesRedisITest.java @@ -0,0 +1,42 @@ +package io.quarkus.redis.devservices.it; + +import java.util.Arrays; + +import javax.inject.Inject; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import io.quarkus.redis.client.RedisClient; +import io.quarkus.redis.devservices.it.profiles.DevServiceRedis; +import io.quarkus.redis.devservices.it.utils.SocketKit; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; + +@QuarkusTest +@TestProfile(DevServiceRedis.class) +public class DevServicesRedisITest { + + @Inject + RedisClient redisClient; + + @BeforeEach + public void setUp() { + redisClient.set(Arrays.asList("anykey", "anyvalue")); + } + + @Test + @DisplayName("given quarkus.redis.hosts disabled should start redis testcontainer") + public void shouldStartRedisContainer() { + Assertions.assertTrue(SocketKit.isPortAlreadyUsed(6379)); + } + + @Test + @DisplayName("given redis container must communicate with it and return value by key") + public void shouldReturnAllKeys() { + Assertions.assertEquals("anyvalue", redisClient.get("anykey").toString()); + } + +} diff --git a/integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/profiles/DevServiceRedis.java b/integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/profiles/DevServiceRedis.java new file mode 100644 index 0000000000000..8ca694a5347ef --- /dev/null +++ b/integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/profiles/DevServiceRedis.java @@ -0,0 +1,14 @@ +package io.quarkus.redis.devservices.it.profiles; + +import java.util.Collections; +import java.util.Map; + +import io.quarkus.test.junit.QuarkusTestProfile; + +public class DevServiceRedis implements QuarkusTestProfile { + + @Override + public Map getConfigOverrides() { + return Collections.singletonMap("quarkus.redis.devservices.port", "6379"); + } +} diff --git a/integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/profiles/DevServicesCustomPortProfile.java b/integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/profiles/DevServicesCustomPortProfile.java new file mode 100644 index 0000000000000..cc68897d1fde9 --- /dev/null +++ b/integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/profiles/DevServicesCustomPortProfile.java @@ -0,0 +1,19 @@ +package io.quarkus.redis.devservices.it.profiles; + +import java.util.Collections; +import java.util.Map; + +import io.quarkus.test.junit.QuarkusTestProfile; + +public class DevServicesCustomPortProfile implements QuarkusTestProfile { + + @Override + public Map getConfigOverrides() { + return Collections.singletonMap("quarkus.redis.devservices.port", "6371"); + } + + @Override + public String getConfigProfile() { + return "test"; + } +} diff --git a/integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/profiles/DevServicesDisabledProfile.java b/integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/profiles/DevServicesDisabledProfile.java new file mode 100644 index 0000000000000..aa1f4d4198ac9 --- /dev/null +++ b/integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/profiles/DevServicesDisabledProfile.java @@ -0,0 +1,19 @@ +package io.quarkus.redis.devservices.it.profiles; + +import java.util.Collections; +import java.util.Map; + +import io.quarkus.test.junit.QuarkusTestProfile; + +public class DevServicesDisabledProfile implements QuarkusTestProfile { + + @Override + public Map getConfigOverrides() { + return Collections.singletonMap("quarkus.redis.devservices.enabled", "false"); + } + + @Override + public String getConfigProfile() { + return "test"; + } +} diff --git a/integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/utils/SocketKit.java b/integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/utils/SocketKit.java new file mode 100644 index 0000000000000..58bb62a0de7b5 --- /dev/null +++ b/integration-tests/redis-devservices/src/test/java/io/quarkus/redis/devservices/it/utils/SocketKit.java @@ -0,0 +1,16 @@ +package io.quarkus.redis.devservices.it.utils; + +import java.io.IOException; +import java.net.Socket; + +public class SocketKit { + + public static boolean isPortAlreadyUsed(Integer port) { + try (Socket ignored = new Socket("localhost", port)) { + ignored.close(); + return true; + } catch (IOException ignored) { + return false; + } + } +} From 723fa4491b7d9fc94c672364c83a8c68a5c5827d Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Wed, 12 May 2021 12:08:59 -0300 Subject: [PATCH 0054/2077] Introduce quarkus.jackson.accept-case-insensitive-enums If enabled, Jackson will ignore case during Enum deserialization. --- ...JacksonAcceptCaseInsensitiveEnumsTest.java | 48 +++++++++++++++++++ ...n-accept-case-insensitive-enums.properties | 1 + .../runtime/JacksonBuildTimeConfig.java | 6 +++ .../jackson/runtime/JacksonConfigSupport.java | 10 +++- .../jackson/runtime/JacksonRecorder.java | 3 +- .../jackson/runtime/ObjectMapperProducer.java | 4 ++ 6 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 extensions/jackson/deployment/src/test/java/io/quarkus/jackson/deployment/JacksonAcceptCaseInsensitiveEnumsTest.java create mode 100644 extensions/jackson/deployment/src/test/resources/application-accept-case-insensitive-enums.properties diff --git a/extensions/jackson/deployment/src/test/java/io/quarkus/jackson/deployment/JacksonAcceptCaseInsensitiveEnumsTest.java b/extensions/jackson/deployment/src/test/java/io/quarkus/jackson/deployment/JacksonAcceptCaseInsensitiveEnumsTest.java new file mode 100644 index 0000000000000..4f924ca5f476b --- /dev/null +++ b/extensions/jackson/deployment/src/test/java/io/quarkus/jackson/deployment/JacksonAcceptCaseInsensitiveEnumsTest.java @@ -0,0 +1,48 @@ +package io.quarkus.jackson.deployment; + +import static org.assertj.core.api.Assertions.assertThat; + +import javax.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import io.quarkus.test.QuarkusUnitTest; + +public class JacksonAcceptCaseInsensitiveEnumsTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withConfigurationResource("application-accept-case-insensitive-enums.properties"); + + @Inject + ObjectMapper objectMapper; + + @Test + public void testAcceptCaseInsensitiveEnums() throws JsonProcessingException { + // Test upper case + TestObject uppercase = objectMapper.readValue("{ \"testEnum\": \"ONE\" }", TestObject.class); + assertThat(uppercase.testEnum).isEqualTo(TestEnum.ONE); + + // Test lower case + TestObject lowercase = objectMapper.readValue("{ \"testEnum\": \"one\" }", TestObject.class); + assertThat(lowercase.testEnum).isEqualTo(TestEnum.ONE); + + // Test mixed case + TestObject mixedcase = objectMapper.readValue("{ \"testEnum\": \"oNe\" }", TestObject.class); + assertThat(mixedcase.testEnum).isEqualTo(TestEnum.ONE); + } + + private enum TestEnum { + ONE, + TWO + } + + private static class TestObject { + public TestEnum testEnum; + } + +} diff --git a/extensions/jackson/deployment/src/test/resources/application-accept-case-insensitive-enums.properties b/extensions/jackson/deployment/src/test/resources/application-accept-case-insensitive-enums.properties new file mode 100644 index 0000000000000..61a1e1904b617 --- /dev/null +++ b/extensions/jackson/deployment/src/test/resources/application-accept-case-insensitive-enums.properties @@ -0,0 +1 @@ +quarkus.jackson.accept-case-insensitive-enums=true diff --git a/extensions/jackson/runtime/src/main/java/io/quarkus/jackson/runtime/JacksonBuildTimeConfig.java b/extensions/jackson/runtime/src/main/java/io/quarkus/jackson/runtime/JacksonBuildTimeConfig.java index 5ff4cd869cc2e..f056682c94361 100644 --- a/extensions/jackson/runtime/src/main/java/io/quarkus/jackson/runtime/JacksonBuildTimeConfig.java +++ b/extensions/jackson/runtime/src/main/java/io/quarkus/jackson/runtime/JacksonBuildTimeConfig.java @@ -23,6 +23,12 @@ public class JacksonBuildTimeConfig { @ConfigItem(defaultValue = "false") public boolean writeDatesAsTimestamps; + /** + * If enabled, Jackson will ignore case during Enum deserialization. + */ + @ConfigItem(defaultValue = "false") + public boolean acceptCaseInsensitiveEnums; + /** * If set, Jackson will default to using the specified timezone when formatting dates. * Some examples values are "Asia/Jakarta" and "GMT+3". diff --git a/extensions/jackson/runtime/src/main/java/io/quarkus/jackson/runtime/JacksonConfigSupport.java b/extensions/jackson/runtime/src/main/java/io/quarkus/jackson/runtime/JacksonConfigSupport.java index 82ba9ffcbe55a..9e4172579643e 100644 --- a/extensions/jackson/runtime/src/main/java/io/quarkus/jackson/runtime/JacksonConfigSupport.java +++ b/extensions/jackson/runtime/src/main/java/io/quarkus/jackson/runtime/JacksonConfigSupport.java @@ -8,11 +8,15 @@ public class JacksonConfigSupport { private final boolean writeDatesAsTimestamps; + private final boolean acceptCaseInsensitiveEnums; + private final ZoneId timeZone; - public JacksonConfigSupport(boolean failOnUnknownProperties, boolean writeDatesAsTimestamps, ZoneId timeZone) { + public JacksonConfigSupport(boolean failOnUnknownProperties, boolean writeDatesAsTimestamps, + boolean acceptCaseInsensitiveEnums, ZoneId timeZone) { this.failOnUnknownProperties = failOnUnknownProperties; this.writeDatesAsTimestamps = writeDatesAsTimestamps; + this.acceptCaseInsensitiveEnums = acceptCaseInsensitiveEnums; this.timeZone = timeZone; } @@ -24,6 +28,10 @@ public boolean isWriteDatesAsTimestamps() { return writeDatesAsTimestamps; } + public boolean isAcceptCaseInsensitiveEnums() { + return acceptCaseInsensitiveEnums; + } + public ZoneId getTimeZone() { return timeZone; } diff --git a/extensions/jackson/runtime/src/main/java/io/quarkus/jackson/runtime/JacksonRecorder.java b/extensions/jackson/runtime/src/main/java/io/quarkus/jackson/runtime/JacksonRecorder.java index 3784284982632..14e991e95e0d2 100644 --- a/extensions/jackson/runtime/src/main/java/io/quarkus/jackson/runtime/JacksonRecorder.java +++ b/extensions/jackson/runtime/src/main/java/io/quarkus/jackson/runtime/JacksonRecorder.java @@ -13,7 +13,8 @@ public Supplier jacksonConfigSupport(JacksonBuildTimeConfi @Override public JacksonConfigSupport get() { return new JacksonConfigSupport(jacksonBuildTimeConfig.failOnUnknownProperties, - jacksonBuildTimeConfig.writeDatesAsTimestamps, jacksonBuildTimeConfig.timezone.orElse(null)); + jacksonBuildTimeConfig.writeDatesAsTimestamps, jacksonBuildTimeConfig.acceptCaseInsensitiveEnums, + jacksonBuildTimeConfig.timezone.orElse(null)); } }; } diff --git a/extensions/jackson/runtime/src/main/java/io/quarkus/jackson/runtime/ObjectMapperProducer.java b/extensions/jackson/runtime/src/main/java/io/quarkus/jackson/runtime/ObjectMapperProducer.java index 4d9b3cd4f5e5a..cf613a793eed1 100644 --- a/extensions/jackson/runtime/src/main/java/io/quarkus/jackson/runtime/ObjectMapperProducer.java +++ b/extensions/jackson/runtime/src/main/java/io/quarkus/jackson/runtime/ObjectMapperProducer.java @@ -12,6 +12,7 @@ import javax.inject.Singleton; import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; @@ -35,6 +36,9 @@ public ObjectMapper objectMapper(Instance customizers, // this feature is enabled by default, so we disable it objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); } + if (jacksonConfigSupport.isAcceptCaseInsensitiveEnums()) { + objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS); + } ZoneId zoneId = jacksonConfigSupport.getTimeZone(); if ((zoneId != null) && !zoneId.getId().equals("UTC")) { // Jackson uses UTC as the default, so let's not reset it objectMapper.setTimeZone(TimeZone.getTimeZone(zoneId)); From fdc75a8a7a66f1c6842c484fe2593c046a00cfb5 Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Wed, 12 May 2021 13:32:35 -0300 Subject: [PATCH 0055/2077] Make sure that resteasy-reactive uses the same Jackson used in Quarkus Jackson 2.11.3 is resolved transitively because of Vert.x, it should use the same used in Quarkus --- independent-projects/resteasy-reactive/pom.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/independent-projects/resteasy-reactive/pom.xml b/independent-projects/resteasy-reactive/pom.xml index 9371042a7256b..a53b90e47a9af 100644 --- a/independent-projects/resteasy-reactive/pom.xml +++ b/independent-projects/resteasy-reactive/pom.xml @@ -56,6 +56,7 @@ 4.3.3 1.0.0.Final 2.0.0.Final + 2.12.3 @@ -67,6 +68,14 @@ + + + com.fasterxml.jackson + jackson-bom + ${jackson.version} + import + pom + io.quarkus.resteasy.reactive From 2fec26488602dc8834e222f15ece29d590643b7b Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Thu, 6 May 2021 17:24:58 +0100 Subject: [PATCH 0056/2077] Support Multi-Tenancy in Keycloak Authorization --- .../security-keycloak-authorization.adoc | 32 ++++ .../KeycloakPolicyEnforcerBuildStep.java | 51 ++++-- ...KeycloakPoilcyEnforcerBuildTimeConfig.java | 28 +++ .../KeycloakPolicyEnforcerAuthorizer.java | 148 ++------------- .../runtime/KeycloakPolicyEnforcerConfig.java | 169 ++---------------- .../KeycloakPolicyEnforcerConfigBean.java | 22 --- .../KeycloakPolicyEnforcerRecorder.java | 139 +++++++++++++- .../KeycloakPolicyEnforcerTenantConfig.java | 167 +++++++++++++++++ .../pep/runtime/PolicyEnforcerResolver.java | 30 ++++ .../it/keycloak/CustomTenantResolver.java | 19 ++ .../it/keycloak/ProtectedResource.java | 6 + .../it/keycloak/ProtectedTenantResource.java | 32 ++++ .../src/main/resources/application.properties | 25 ++- .../it/keycloak/KeycloakTestResource.java | 17 +- .../it/keycloak/PolicyEnforcerTest.java | 18 ++ 15 files changed, 564 insertions(+), 339 deletions(-) create mode 100644 extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPoilcyEnforcerBuildTimeConfig.java delete mode 100644 extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerConfigBean.java create mode 100644 extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerTenantConfig.java create mode 100644 extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/PolicyEnforcerResolver.java create mode 100644 integration-tests/keycloak-authorization/src/main/java/io/quarkus/it/keycloak/CustomTenantResolver.java create mode 100644 integration-tests/keycloak-authorization/src/main/java/io/quarkus/it/keycloak/ProtectedTenantResource.java diff --git a/docs/src/main/asciidoc/security-keycloak-authorization.adoc b/docs/src/main/asciidoc/security-keycloak-authorization.adoc index ce41da643e554..de4e76ec9ede2 100644 --- a/docs/src/main/asciidoc/security-keycloak-authorization.adoc +++ b/docs/src/main/asciidoc/security-keycloak-authorization.adoc @@ -363,6 +363,38 @@ In the default configuration, Keycloak is responsible for managing the roles and To configure the protected routes using the `@RolesAllowed` annotation or the `application.properties` file, check the link:security-openid-connect[Using OpenID Connect Adapter to Protect JAX-RS Applications] guide. For more details, check the link:security[Security guide]. +== Multi-Tenancy + +It is possible to configure multiple policy enforcer configurations, one per each tenant, similarly to how it can be done for link:security-openid-connect-multitenancy[Multi-Tenant OpenId Connect Service Applications]. + +For example: + +[source,properties] +---- +quarkus.keycloak.policy-enforcer.enable=true + +# Default Tenant +quarkus.oidc.auth-server-url=${keycloak.url}/realms/quarkus +quarkus.oidc.client-id=quarkus-app +quarkus.oidc.credentials.secret=secret + +quarkus.keycloak.policy-enforcer.enforcement-mode=PERMISSIVE +quarkus.keycloak.policy-enforcer.paths.1.name=Permission Resource +quarkus.keycloak.policy-enforcer.paths.1.path=/api/permission +quarkus.keycloak.policy-enforcer.paths.1.claim-information-point.claims.static-claim=static-claim + +# Tenant1 + +quarkus.oidc.tenant1.auth-server-url=${keycloak.url}/realms/quarkus +quarkus.oidc.tenant1.client-id=quarkus-app +quarkus.oidc.tenant1.credentials.secret=secret + +quarkus.keycloak.tenant1.policy-enforcer.enforcement-mode=PERMISSIVE +quarkus.keycloak.tenant1.policy-enforcer.paths.1.name=Permission Resource +quarkus.keycloak.tenant1.policy-enforcer.paths.1.path=/api/permission +quarkus.keycloak.tenant1.policy-enforcer.paths.1.claim-information-point.claims.static-claim=static-claim +---- + == Configuration Reference The configuration is based on the official https://www.keycloak.org/docs/latest/authorization_services/index.html#_enforcer_filter[Keycloak Policy Enforcer Configuration]. If you are looking for more details about the different configuration options, please take a look at this documentation, diff --git a/extensions/keycloak-authorization/deployment/src/main/java/io/quarkus/keycloak/pep/deployment/KeycloakPolicyEnforcerBuildStep.java b/extensions/keycloak-authorization/deployment/src/main/java/io/quarkus/keycloak/pep/deployment/KeycloakPolicyEnforcerBuildStep.java index 070128488a689..b9a9fc54823b4 100644 --- a/extensions/keycloak-authorization/deployment/src/main/java/io/quarkus/keycloak/pep/deployment/KeycloakPolicyEnforcerBuildStep.java +++ b/extensions/keycloak-authorization/deployment/src/main/java/io/quarkus/keycloak/pep/deployment/KeycloakPolicyEnforcerBuildStep.java @@ -1,6 +1,7 @@ package io.quarkus.keycloak.pep.deployment; import java.util.Map; +import java.util.function.BooleanSupplier; import javax.inject.Singleton; @@ -12,10 +13,13 @@ import io.quarkus.deployment.annotations.Record; import io.quarkus.deployment.builditem.ExtensionSslNativeSupportBuildItem; import io.quarkus.deployment.builditem.FeatureBuildItem; +import io.quarkus.keycloak.pep.runtime.KeycloakPoilcyEnforcerBuildTimeConfig; import io.quarkus.keycloak.pep.runtime.KeycloakPolicyEnforcerAuthorizer; import io.quarkus.keycloak.pep.runtime.KeycloakPolicyEnforcerConfig; -import io.quarkus.keycloak.pep.runtime.KeycloakPolicyEnforcerConfigBean; import io.quarkus.keycloak.pep.runtime.KeycloakPolicyEnforcerRecorder; +import io.quarkus.keycloak.pep.runtime.KeycloakPolicyEnforcerTenantConfig; +import io.quarkus.keycloak.pep.runtime.KeycloakPolicyEnforcerTenantConfig.KeycloakConfigPolicyEnforcer.PathConfig; +import io.quarkus.keycloak.pep.runtime.PolicyEnforcerResolver; import io.quarkus.oidc.runtime.OidcBuildTimeConfig; import io.quarkus.oidc.runtime.OidcConfig; import io.quarkus.runtime.TlsConfig; @@ -29,15 +33,14 @@ FeatureBuildItem featureBuildItem() { return new FeatureBuildItem(Feature.KEYCLOAK_AUTHORIZATION); } - @BuildStep + @BuildStep(onlyIf = IsEnabled.class) RequireBodyHandlerBuildItem requireBody(OidcBuildTimeConfig oidcBuildTimeConfig, KeycloakPolicyEnforcerConfig config) { - if (oidcBuildTimeConfig.enabled && config.policyEnforcer.enable) { - if (isBodyClaimInformationPointDefined(config.policyEnforcer.claimInformationPoint.simpleConfig)) { + if (oidcBuildTimeConfig.enabled) { + if (isBodyHandlerRequired(config.defaultTenant)) { return new RequireBodyHandlerBuildItem(); } - for (KeycloakPolicyEnforcerConfig.KeycloakConfigPolicyEnforcer.PathConfig path : config.policyEnforcer.paths - .values()) { - if (isBodyClaimInformationPointDefined(path.claimInformationPoint.simpleConfig)) { + for (KeycloakPolicyEnforcerTenantConfig tenantConfig : config.namedTenants.values()) { + if (isBodyHandlerRequired(tenantConfig)) { return new RequireBodyHandlerBuildItem(); } } @@ -45,7 +48,19 @@ RequireBodyHandlerBuildItem requireBody(OidcBuildTimeConfig oidcBuildTimeConfig, return null; } - private boolean isBodyClaimInformationPointDefined(Map> claims) { + private static boolean isBodyHandlerRequired(KeycloakPolicyEnforcerTenantConfig config) { + if (isBodyClaimInformationPointDefined(config.policyEnforcer.claimInformationPoint.simpleConfig)) { + return true; + } + for (PathConfig path : config.policyEnforcer.paths.values()) { + if (isBodyClaimInformationPointDefined(path.claimInformationPoint.simpleConfig)) { + return true; + } + } + return false; + } + + private static boolean isBodyClaimInformationPointDefined(Map> claims) { for (Map.Entry> entry : claims.entrySet()) { Map value = entry.getValue(); @@ -59,9 +74,9 @@ private boolean isBodyClaimInformationPointDefined(Map { + private static final String TENANT_ID_ATTRIBUTE = "tenant-id"; + private static final String PERMISSIONS_ATTRIBUTE = "permissions"; @Inject - KeycloakPolicyEnforcerConfigBean configBean; - - private KeycloakAdapterPolicyEnforcer delegate; - private PolicyEnforcer policyEnforcer; + PolicyEnforcerResolver resolver; @Override public Uni checkPermission(RoutingContext request, Uni identity, @@ -58,10 +49,11 @@ public CheckResult apply(RoutingContext routingContext, SecurityIdentity identit return CheckResult.PERMIT; } - String token = credential.getToken(); - VertxHttpFacade httpFacade = new VertxHttpFacade(routingContext, token, - configBean.httpConfiguration.readTimeout.toMillis()); - AuthorizationContext result = delegate.authorize(httpFacade); + VertxHttpFacade httpFacade = new VertxHttpFacade(routingContext, credential.getToken(), resolver.getReadTimeout()); + + KeycloakAdapterPolicyEnforcer adapterPolicyEnforcer = new KeycloakAdapterPolicyEnforcer( + resolver.getPolicyEnforcer(identity.getAttribute(TENANT_ID_ATTRIBUTE))); + AuthorizationContext result = adapterPolicyEnforcer.authorize(httpFacade); if (result.isGranted()) { SecurityIdentity newIdentity = enhanceSecurityIdentity(identity, result); @@ -72,9 +64,10 @@ public CheckResult apply(RoutingContext routingContext, SecurityIdentity identit } @Produces - @ApplicationScoped + @RequestScoped public AuthzClient getAuthzClient() { - return policyEnforcer.getClient(); + SecurityIdentity identity = (SecurityIdentity) Arc.container().instance(SecurityIdentity.class).get(); + return resolver.getPolicyEnforcer(identity.getAttribute(TENANT_ID_ATTRIBUTE)).getClient(); } private SecurityIdentity enhanceSecurityIdentity(SecurityIdentity current, @@ -82,7 +75,7 @@ private SecurityIdentity enhanceSecurityIdentity(SecurityIdentity current, Map attributes = new HashMap<>(current.getAttributes()); if (context != null) { - attributes.put("permissions", context.getPermissions()); + attributes.put(PERMISSIONS_ATTRIBUTE, context.getPermissions()); } return new QuarkusSecurityIdentity.Builder() @@ -113,117 +106,4 @@ public Uni apply(Permission permission) { } }).build(); } - - @PostConstruct - public void init() { - AdapterConfig adapterConfig = new AdapterConfig(); - String authServerUrl = configBean.oidcConfig.defaultTenant.getAuthServerUrl().get(); - - try { - adapterConfig.setRealm(authServerUrl.substring(authServerUrl.lastIndexOf('/') + 1)); - adapterConfig.setAuthServerUrl(authServerUrl.substring(0, authServerUrl.lastIndexOf("/realms"))); - } catch (Exception cause) { - throw new RuntimeException("Failed to parse the realm name.", cause); - } - - adapterConfig.setResource(configBean.oidcConfig.defaultTenant.getClientId().get()); - adapterConfig.setCredentials(getCredentials(configBean.oidcConfig.defaultTenant)); - - boolean trustAll = configBean.oidcConfig.defaultTenant.tls.getVerification().isPresent() - ? configBean.oidcConfig.defaultTenant.tls.getVerification().get() == Verification.NONE - : configBean.tlsConfig.trustAll; - if (trustAll) { - adapterConfig.setDisableTrustManager(true); - adapterConfig.setAllowAnyHostname(true); - } - - if (configBean.oidcConfig.defaultTenant.proxy.host.isPresent()) { - adapterConfig.setProxyUrl(configBean.oidcConfig.defaultTenant.proxy.host.get() + ":" - + configBean.oidcConfig.defaultTenant.proxy.port); - } - - PolicyEnforcerConfig enforcerConfig = getPolicyEnforcerConfig(configBean.keycloakPolicyEnforcerConfig, - adapterConfig); - - if (enforcerConfig == null) { - return; - } - - adapterConfig.setPolicyEnforcerConfig(enforcerConfig); - - policyEnforcer = new PolicyEnforcer(KeycloakDeploymentBuilder.build(adapterConfig), adapterConfig); - delegate = new KeycloakAdapterPolicyEnforcer(policyEnforcer); - } - - private Map getCredentials(OidcTenantConfig oidcConfig) { - Map credentials = new HashMap<>(); - Optional clientSecret = oidcConfig.getCredentials().getSecret(); - - if (clientSecret.isPresent()) { - credentials.put("secret", clientSecret.orElse(null)); - } - - return credentials; - } - - private Map> getClaimInformationPointConfig( - KeycloakPolicyEnforcerConfig.KeycloakConfigPolicyEnforcer.ClaimInformationPointConfig config) { - Map> cipConfig = new HashMap<>(); - - for (Map.Entry> entry : config.simpleConfig.entrySet()) { - cipConfig.put(entry.getKey(), new HashMap<>(entry.getValue())); - } - - for (Map.Entry>> entry : config.complexConfig.entrySet()) { - cipConfig.computeIfAbsent(entry.getKey(), s -> new HashMap<>()).putAll(new HashMap<>(entry.getValue())); - } - - return cipConfig; - } - - private PolicyEnforcerConfig getPolicyEnforcerConfig(KeycloakPolicyEnforcerConfig config, AdapterConfig adapterConfig) { - if (config.policyEnforcer != null && config.policyEnforcer.enable) { - PolicyEnforcerConfig enforcerConfig = new PolicyEnforcerConfig(); - - enforcerConfig.setLazyLoadPaths(config.policyEnforcer.lazyLoadPaths); - enforcerConfig.setEnforcementMode(config.policyEnforcer.enforcementMode); - enforcerConfig.setHttpMethodAsScope(config.policyEnforcer.httpMethodAsScope); - - KeycloakPolicyEnforcerConfig.KeycloakConfigPolicyEnforcer.PathCacheConfig pathCache = config.policyEnforcer.pathCache; - - PolicyEnforcerConfig.PathCacheConfig pathCacheConfig = new PolicyEnforcerConfig.PathCacheConfig(); - pathCacheConfig.setLifespan(pathCache.lifespan); - pathCacheConfig.setMaxEntries(pathCache.maxEntries); - enforcerConfig.setPathCacheConfig(pathCacheConfig); - - enforcerConfig.setClaimInformationPointConfig( - getClaimInformationPointConfig(config.policyEnforcer.claimInformationPoint)); - enforcerConfig.setPaths(config.policyEnforcer.paths.values().stream().map( - pathConfig -> { - PolicyEnforcerConfig.PathConfig config1 = new PolicyEnforcerConfig.PathConfig(); - - config1.setName(pathConfig.name.orElse(null)); - config1.setPath(pathConfig.path.orElse(null)); - config1.setEnforcementMode(pathConfig.enforcementMode); - config1.setMethods(pathConfig.methods.values().stream().map( - methodConfig -> { - PolicyEnforcerConfig.MethodConfig mConfig = new PolicyEnforcerConfig.MethodConfig(); - - mConfig.setMethod(methodConfig.method); - mConfig.setScopes(methodConfig.scopes); - mConfig.setScopesEnforcementMode(methodConfig.scopesEnforcementMode); - - return mConfig; - }).collect(Collectors.toList())); - config1.setClaimInformationPointConfig( - getClaimInformationPointConfig(pathConfig.claimInformationPoint)); - - return config1; - }).collect(Collectors.toList())); - - return enforcerConfig; - } - - return null; - } } diff --git a/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerConfig.java b/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerConfig.java index c6a77d4ea35ae..e33c0b882f394 100644 --- a/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerConfig.java +++ b/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerConfig.java @@ -1,12 +1,9 @@ package io.quarkus.keycloak.pep.runtime; -import java.util.List; import java.util.Map; -import java.util.Optional; -import org.keycloak.representations.adapters.config.PolicyEnforcerConfig; - -import io.quarkus.runtime.annotations.ConfigGroup; +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; @@ -15,162 +12,16 @@ public class KeycloakPolicyEnforcerConfig { /** - * Adapters will make separate HTTP invocations to the Keycloak server to turn an access code into an access token. - * This config option defines how many connections to the Keycloak server should be pooled + * The default tenant. */ - @ConfigItem(defaultValue = "20") - int connectionPoolSize; + @ConfigItem(name = ConfigItem.PARENT) + public KeycloakPolicyEnforcerTenantConfig defaultTenant; /** - * Policy enforcement configuration when using Keycloak Authorization Services + * Additional named tenants. */ - @ConfigItem - public KeycloakConfigPolicyEnforcer policyEnforcer; - - @ConfigGroup - public static class KeycloakConfigPolicyEnforcer { - - /** - * Enables policy enforcement. - */ - @ConfigItem - public boolean enable; - - /** - * Specifies how policies are enforced. - */ - @ConfigItem(defaultValue = "enforcing") - public PolicyEnforcerConfig.EnforcementMode enforcementMode; - - /** - * Specifies the paths to protect. - */ - @ConfigItem - public Map paths; - - /** - * Defines how the policy enforcer should track associations between paths in your application and resources defined in - * Keycloak. - * The cache is needed to avoid unnecessary requests to a Keycloak server by caching associations between paths and - * protected resources - */ - @ConfigItem - public PathCacheConfig pathCache = new PathCacheConfig(); - - /** - * Specifies how the adapter should fetch the server for resources associated with paths in your application. If true, - * the - * policy - * enforcer is going to fetch resources on-demand accordingly with the path being requested - */ - @ConfigItem(defaultValue = "true") - public boolean lazyLoadPaths; - - /** - * Defines a set of one or more claims that must be resolved and pushed to the Keycloak server in order to make these - * claims available to policies - */ - @ConfigItem - public ClaimInformationPointConfig claimInformationPoint; - - /** - * Specifies how scopes should be mapped to HTTP methods. If set to true, the policy enforcer will use the HTTP method - * from - * the current request to check whether or not access should be granted - */ - @ConfigItem - public boolean httpMethodAsScope; - - @ConfigGroup - public static class PathConfig { - - /** - * The name of a resource on the server that is to be associated with a given path - */ - @ConfigItem - public Optional name; - - /** - * A URI relative to the application’s context path that should be protected by the policy enforcer - */ - @ConfigItem - public Optional path; - - /** - * The HTTP methods (for example, GET, POST, PATCH) to protect and how they are associated with the scopes for a - * given - * resource in the server - */ - @ConfigItem - public Map methods; - - /** - * Specifies how policies are enforced - */ - @ConfigItem(defaultValue = "enforcing") - public PolicyEnforcerConfig.EnforcementMode enforcementMode; - - /** - * Defines a set of one or more claims that must be resolved and pushed to the Keycloak server in order to make - * these - * claims available to policies - */ - @ConfigItem - public ClaimInformationPointConfig claimInformationPoint; - } - - @ConfigGroup - public static class MethodConfig { - - /** - * The name of the HTTP method - */ - @ConfigItem - public String method; - - /** - * An array of strings with the scopes associated with the method - */ - @ConfigItem - public List scopes; - - /** - * A string referencing the enforcement mode for the scopes associated with a method - */ - @ConfigItem(defaultValue = "all") - public PolicyEnforcerConfig.ScopeEnforcementMode scopesEnforcementMode; - } - - @ConfigGroup - public static class PathCacheConfig { - - /** - * Defines the limit of entries that should be kept in the cache - */ - @ConfigItem(defaultValue = "1000") - public int maxEntries = 1000; - - /** - * Defines the time in milliseconds when the entry should be expired - */ - @ConfigItem(defaultValue = "30000") - public long lifespan = 30000; - } - - @ConfigGroup - public static class ClaimInformationPointConfig { - - /** - * - */ - @ConfigItem(name = ConfigItem.PARENT) - public Map>> complexConfig; - - /** - * - */ - @ConfigItem(name = ConfigItem.PARENT) - public Map> simpleConfig; - } - } + @ConfigDocSection + @ConfigDocMapKey("tenant") + @ConfigItem(name = ConfigItem.PARENT) + public Map namedTenants; } diff --git a/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerConfigBean.java b/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerConfigBean.java deleted file mode 100644 index 0dbb1217c6239..0000000000000 --- a/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerConfigBean.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.quarkus.keycloak.pep.runtime; - -import io.quarkus.oidc.runtime.OidcConfig; -import io.quarkus.runtime.TlsConfig; -import io.quarkus.vertx.http.runtime.HttpConfiguration; - -public class KeycloakPolicyEnforcerConfigBean { - - final OidcConfig oidcConfig; - final KeycloakPolicyEnforcerConfig keycloakPolicyEnforcerConfig; - final TlsConfig tlsConfig; - final HttpConfiguration httpConfiguration; - - public KeycloakPolicyEnforcerConfigBean(OidcConfig oidcConfig, KeycloakPolicyEnforcerConfig keycloakPolicyEnforcerConfig, - TlsConfig tlsConfig, - HttpConfiguration httpConfiguration) { - this.oidcConfig = oidcConfig; - this.keycloakPolicyEnforcerConfig = keycloakPolicyEnforcerConfig; - this.tlsConfig = tlsConfig; - this.httpConfiguration = httpConfiguration; - } -} diff --git a/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerRecorder.java b/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerRecorder.java index 712995e8015a1..47a4fef63b0a5 100644 --- a/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerRecorder.java +++ b/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerRecorder.java @@ -1,27 +1,158 @@ package io.quarkus.keycloak.pep.runtime; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; import java.util.function.Supplier; +import java.util.stream.Collectors; +import org.keycloak.adapters.KeycloakDeploymentBuilder; +import org.keycloak.adapters.authorization.PolicyEnforcer; +import org.keycloak.representations.adapters.config.AdapterConfig; +import org.keycloak.representations.adapters.config.PolicyEnforcerConfig; + +import io.quarkus.keycloak.pep.runtime.KeycloakPolicyEnforcerTenantConfig.KeycloakConfigPolicyEnforcer.ClaimInformationPointConfig; +import io.quarkus.keycloak.pep.runtime.KeycloakPolicyEnforcerTenantConfig.KeycloakConfigPolicyEnforcer.PathCacheConfig; import io.quarkus.oidc.OIDCException; import io.quarkus.oidc.OidcTenantConfig; +import io.quarkus.oidc.common.runtime.OidcCommonConfig.Tls.Verification; import io.quarkus.oidc.runtime.OidcConfig; import io.quarkus.runtime.TlsConfig; import io.quarkus.runtime.annotations.Recorder; +import io.quarkus.runtime.configuration.ConfigurationException; import io.quarkus.vertx.http.runtime.HttpConfiguration; @Recorder public class KeycloakPolicyEnforcerRecorder { - public Supplier setup(OidcConfig oidcConfig, KeycloakPolicyEnforcerConfig config, + public Supplier setup(OidcConfig oidcConfig, KeycloakPolicyEnforcerConfig config, TlsConfig tlsConfig, HttpConfiguration httpConfiguration) { if (oidcConfig.defaultTenant.applicationType == OidcTenantConfig.ApplicationType.WEB_APP) { throw new OIDCException("Application type [" + oidcConfig.defaultTenant.applicationType + "] is not supported"); } - return new Supplier() { + PolicyEnforcer defaultPolicyEnforcer = createPolicyEnforcer(oidcConfig.defaultTenant, config.defaultTenant, tlsConfig, + httpConfiguration); + Map policyEnforcerTenants = new HashMap(); + for (Map.Entry tenant : config.namedTenants.entrySet()) { + OidcTenantConfig oidcTenantConfig = oidcConfig.namedTenants.get(tenant.getKey()); + if (oidcTenantConfig == null) { + throw new ConfigurationException("Failed to find a matching OidcTenantConfig for tenant: " + tenant.getKey()); + } + policyEnforcerTenants.put(tenant.getKey(), createPolicyEnforcer(oidcTenantConfig, tenant.getValue(), tlsConfig, + httpConfiguration)); + } + return new Supplier() { @Override - public KeycloakPolicyEnforcerConfigBean get() { - return new KeycloakPolicyEnforcerConfigBean(oidcConfig, config, tlsConfig, httpConfiguration); + public PolicyEnforcerResolver get() { + return new PolicyEnforcerResolver(defaultPolicyEnforcer, policyEnforcerTenants, + httpConfiguration.readTimeout.toMillis()); } }; } + + private static PolicyEnforcer createPolicyEnforcer(OidcTenantConfig oidcConfig, + KeycloakPolicyEnforcerTenantConfig keycloakPolicyEnforcerConfig, + TlsConfig tlsConfig, HttpConfiguration httpConfiguration) { + AdapterConfig adapterConfig = new AdapterConfig(); + String authServerUrl = oidcConfig.getAuthServerUrl().get(); + + try { + adapterConfig.setRealm(authServerUrl.substring(authServerUrl.lastIndexOf('/') + 1)); + adapterConfig.setAuthServerUrl(authServerUrl.substring(0, authServerUrl.lastIndexOf("/realms"))); + } catch (Exception cause) { + throw new ConfigurationException("Failed to parse the realm name.", cause); + } + + adapterConfig.setResource(oidcConfig.getClientId().get()); + adapterConfig.setCredentials(getCredentials(oidcConfig)); + + boolean trustAll = oidcConfig.tls.getVerification().isPresent() + ? oidcConfig.tls.getVerification().get() == Verification.NONE + : tlsConfig.trustAll; + if (trustAll) { + adapterConfig.setDisableTrustManager(true); + adapterConfig.setAllowAnyHostname(true); + } + adapterConfig.setConnectionPoolSize(keycloakPolicyEnforcerConfig.connectionPoolSize); + + if (oidcConfig.proxy.host.isPresent()) { + adapterConfig.setProxyUrl(oidcConfig.proxy.host.get() + ":" + + oidcConfig.proxy.port); + } + + PolicyEnforcerConfig enforcerConfig = getPolicyEnforcerConfig(keycloakPolicyEnforcerConfig, + adapterConfig); + + adapterConfig.setPolicyEnforcerConfig(enforcerConfig); + + return new PolicyEnforcer(KeycloakDeploymentBuilder.build(adapterConfig), adapterConfig); + } + + private static Map getCredentials(OidcTenantConfig oidcConfig) { + Map credentials = new HashMap<>(); + Optional clientSecret = oidcConfig.getCredentials().getSecret(); + + if (clientSecret.isPresent()) { + credentials.put("secret", clientSecret.orElse(null)); + } + + return credentials; + } + + private static Map> getClaimInformationPointConfig(ClaimInformationPointConfig config) { + Map> cipConfig = new HashMap<>(); + + for (Map.Entry> entry : config.simpleConfig.entrySet()) { + cipConfig.put(entry.getKey(), new HashMap<>(entry.getValue())); + } + + for (Map.Entry>> entry : config.complexConfig.entrySet()) { + cipConfig.computeIfAbsent(entry.getKey(), s -> new HashMap<>()).putAll(new HashMap<>(entry.getValue())); + } + + return cipConfig; + } + + private static PolicyEnforcerConfig getPolicyEnforcerConfig(KeycloakPolicyEnforcerTenantConfig config, + AdapterConfig adapterConfig) { + PolicyEnforcerConfig enforcerConfig = new PolicyEnforcerConfig(); + + enforcerConfig.setLazyLoadPaths(config.policyEnforcer.lazyLoadPaths); + enforcerConfig.setEnforcementMode(config.policyEnforcer.enforcementMode); + enforcerConfig.setHttpMethodAsScope(config.policyEnforcer.httpMethodAsScope); + + PathCacheConfig pathCache = config.policyEnforcer.pathCache; + + PolicyEnforcerConfig.PathCacheConfig pathCacheConfig = new PolicyEnforcerConfig.PathCacheConfig(); + pathCacheConfig.setLifespan(pathCache.lifespan); + pathCacheConfig.setMaxEntries(pathCache.maxEntries); + enforcerConfig.setPathCacheConfig(pathCacheConfig); + + enforcerConfig.setClaimInformationPointConfig( + getClaimInformationPointConfig(config.policyEnforcer.claimInformationPoint)); + enforcerConfig.setPaths(config.policyEnforcer.paths.values().stream().map( + pathConfig -> { + PolicyEnforcerConfig.PathConfig config1 = new PolicyEnforcerConfig.PathConfig(); + + config1.setName(pathConfig.name.orElse(null)); + config1.setPath(pathConfig.path.orElse(null)); + config1.setEnforcementMode(pathConfig.enforcementMode); + config1.setMethods(pathConfig.methods.values().stream().map( + methodConfig -> { + PolicyEnforcerConfig.MethodConfig mConfig = new PolicyEnforcerConfig.MethodConfig(); + + mConfig.setMethod(methodConfig.method); + mConfig.setScopes(methodConfig.scopes); + mConfig.setScopesEnforcementMode(methodConfig.scopesEnforcementMode); + + return mConfig; + }).collect(Collectors.toList())); + config1.setClaimInformationPointConfig( + getClaimInformationPointConfig(pathConfig.claimInformationPoint)); + + return config1; + }).collect(Collectors.toList())); + + return enforcerConfig; + } } diff --git a/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerTenantConfig.java b/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerTenantConfig.java new file mode 100644 index 0000000000000..ba5e5e74e7937 --- /dev/null +++ b/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerTenantConfig.java @@ -0,0 +1,167 @@ +package io.quarkus.keycloak.pep.runtime; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.keycloak.representations.adapters.config.PolicyEnforcerConfig; + +import io.quarkus.runtime.annotations.ConfigGroup; +import io.quarkus.runtime.annotations.ConfigItem; + +@ConfigGroup +public class KeycloakPolicyEnforcerTenantConfig { + + /** + * Adapters will make separate HTTP invocations to the Keycloak server to turn an access code into an access token. + * This config option defines how many connections to the Keycloak server should be pooled + */ + @ConfigItem(defaultValue = "20") + int connectionPoolSize; + + /** + * Policy enforcement configuration when using Keycloak Authorization Services + */ + @ConfigItem + public KeycloakConfigPolicyEnforcer policyEnforcer = new KeycloakConfigPolicyEnforcer(); + + @ConfigGroup + public static class KeycloakConfigPolicyEnforcer { + /** + * Specifies how policies are enforced. + */ + @ConfigItem(defaultValue = "enforcing") + public PolicyEnforcerConfig.EnforcementMode enforcementMode; + + /** + * Specifies the paths to protect. + */ + @ConfigItem + public Map paths; + + /** + * Defines how the policy enforcer should track associations between paths in your application and resources defined in + * Keycloak. + * The cache is needed to avoid unnecessary requests to a Keycloak server by caching associations between paths and + * protected resources + */ + @ConfigItem + public PathCacheConfig pathCache = new PathCacheConfig(); + + /** + * Specifies how the adapter should fetch the server for resources associated with paths in your application. If true, + * the + * policy + * enforcer is going to fetch resources on-demand accordingly with the path being requested + */ + @ConfigItem(defaultValue = "true") + public boolean lazyLoadPaths; + + /** + * Defines a set of one or more claims that must be resolved and pushed to the Keycloak server in order to make these + * claims available to policies + */ + @ConfigItem + public ClaimInformationPointConfig claimInformationPoint; + + /** + * Specifies how scopes should be mapped to HTTP methods. If set to true, the policy enforcer will use the HTTP method + * from + * the current request to check whether or not access should be granted + */ + @ConfigItem + public boolean httpMethodAsScope; + + @ConfigGroup + public static class PathConfig { + + /** + * The name of a resource on the server that is to be associated with a given path + */ + @ConfigItem + public Optional name; + + /** + * A URI relative to the application’s context path that should be protected by the policy enforcer + */ + @ConfigItem + public Optional path; + + /** + * The HTTP methods (for example, GET, POST, PATCH) to protect and how they are associated with the scopes for a + * given + * resource in the server + */ + @ConfigItem + public Map methods; + + /** + * Specifies how policies are enforced + */ + @ConfigItem(defaultValue = "enforcing") + public PolicyEnforcerConfig.EnforcementMode enforcementMode; + + /** + * Defines a set of one or more claims that must be resolved and pushed to the Keycloak server in order to make + * these + * claims available to policies + */ + @ConfigItem + public ClaimInformationPointConfig claimInformationPoint; + } + + @ConfigGroup + public static class MethodConfig { + + /** + * The name of the HTTP method + */ + @ConfigItem + public String method; + + /** + * An array of strings with the scopes associated with the method + */ + @ConfigItem + public List scopes; + + /** + * A string referencing the enforcement mode for the scopes associated with a method + */ + @ConfigItem(defaultValue = "all") + public PolicyEnforcerConfig.ScopeEnforcementMode scopesEnforcementMode; + } + + @ConfigGroup + public static class PathCacheConfig { + + /** + * Defines the limit of entries that should be kept in the cache + */ + @ConfigItem(defaultValue = "1000") + public int maxEntries = 1000; + + /** + * Defines the time in milliseconds when the entry should be expired + */ + @ConfigItem(defaultValue = "30000") + public long lifespan = 30000; + } + + @ConfigGroup + public static class ClaimInformationPointConfig { + + /** + * + */ + @ConfigItem(name = ConfigItem.PARENT) + public Map>> complexConfig; + + /** + * + */ + @ConfigItem(name = ConfigItem.PARENT) + public Map> simpleConfig; + } + } +} diff --git a/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/PolicyEnforcerResolver.java b/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/PolicyEnforcerResolver.java new file mode 100644 index 0000000000000..ea7c5f056f968 --- /dev/null +++ b/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/PolicyEnforcerResolver.java @@ -0,0 +1,30 @@ +package io.quarkus.keycloak.pep.runtime; + +import java.util.Map; + +import org.keycloak.adapters.authorization.PolicyEnforcer; + +public class PolicyEnforcerResolver { + + private final PolicyEnforcer defaultPolicyEnforcer; + private final Map policyEnforcerTenants; + private final long readTimeout; + + public PolicyEnforcerResolver(PolicyEnforcer defaultPolicyEnforcer, + Map policyEnforcerTenants, + final long readTimeout) { + this.defaultPolicyEnforcer = defaultPolicyEnforcer; + this.policyEnforcerTenants = policyEnforcerTenants; + this.readTimeout = readTimeout; + } + + public PolicyEnforcer getPolicyEnforcer(String tenantId) { + return tenantId != null && policyEnforcerTenants.containsKey(tenantId) + ? policyEnforcerTenants.get(tenantId) + : defaultPolicyEnforcer; + } + + public long getReadTimeout() { + return readTimeout; + } +} diff --git a/integration-tests/keycloak-authorization/src/main/java/io/quarkus/it/keycloak/CustomTenantResolver.java b/integration-tests/keycloak-authorization/src/main/java/io/quarkus/it/keycloak/CustomTenantResolver.java new file mode 100644 index 0000000000000..d93d10cf49e60 --- /dev/null +++ b/integration-tests/keycloak-authorization/src/main/java/io/quarkus/it/keycloak/CustomTenantResolver.java @@ -0,0 +1,19 @@ +package io.quarkus.it.keycloak; + +import javax.enterprise.context.ApplicationScoped; + +import io.quarkus.oidc.TenantResolver; +import io.vertx.ext.web.RoutingContext; + +@ApplicationScoped +public class CustomTenantResolver implements TenantResolver { + + @Override + public String resolve(RoutingContext context) { + if (context.request().path().endsWith("tenant")) { + return "tenant"; + } + + return null; + } +} diff --git a/integration-tests/keycloak-authorization/src/main/java/io/quarkus/it/keycloak/ProtectedResource.java b/integration-tests/keycloak-authorization/src/main/java/io/quarkus/it/keycloak/ProtectedResource.java index c01e112aee21e..74ca2b7e5583a 100644 --- a/integration-tests/keycloak-authorization/src/main/java/io/quarkus/it/keycloak/ProtectedResource.java +++ b/integration-tests/keycloak-authorization/src/main/java/io/quarkus/it/keycloak/ProtectedResource.java @@ -30,6 +30,12 @@ public class ProtectedResource { @Inject AuthzClient authzClient; + @GET + @Path("/tenant") + public Uni> permissionsTenant() { + return permissions(); + } + @GET public Uni> permissions() { return identity.checkPermission(new AuthPermission("Permission Resource")).onItem() diff --git a/integration-tests/keycloak-authorization/src/main/java/io/quarkus/it/keycloak/ProtectedTenantResource.java b/integration-tests/keycloak-authorization/src/main/java/io/quarkus/it/keycloak/ProtectedTenantResource.java new file mode 100644 index 0000000000000..8a59bee71de7e --- /dev/null +++ b/integration-tests/keycloak-authorization/src/main/java/io/quarkus/it/keycloak/ProtectedTenantResource.java @@ -0,0 +1,32 @@ +package io.quarkus.it.keycloak; + +import java.util.List; + +import javax.inject.Inject; +import javax.security.auth.AuthPermission; +import javax.ws.rs.ForbiddenException; +import javax.ws.rs.GET; +import javax.ws.rs.Path; + +import org.keycloak.representations.idm.authorization.Permission; + +import io.quarkus.security.identity.SecurityIdentity; +import io.smallrye.mutiny.Uni; + +@Path("/api-permission-tenant") +public class ProtectedTenantResource { + + @Inject + SecurityIdentity identity; + + @GET + public Uni> permissions() { + return identity.checkPermission(new AuthPermission("Permission Resource Tenant")).onItem() + .transform(granted -> { + if (granted) { + return identity.getAttribute("permissions"); + } + throw new ForbiddenException(); + }); + } +} diff --git a/integration-tests/keycloak-authorization/src/main/resources/application.properties b/integration-tests/keycloak-authorization/src/main/resources/application.properties index 568b85b675e0c..9a0f62e8ba518 100644 --- a/integration-tests/keycloak-authorization/src/main/resources/application.properties +++ b/integration-tests/keycloak-authorization/src/main/resources/application.properties @@ -1,11 +1,12 @@ +# Enable Policy Enforcement +quarkus.keycloak.policy-enforcer.enable=true + +# Default Tenant # Configuration file quarkus.oidc.auth-server-url=${keycloak.url}/realms/quarkus quarkus.oidc.client-id=quarkus-app quarkus.oidc.credentials.secret=secret -quarkus.http.cors=true -# Enable Policy Enforcement -quarkus.keycloak.policy-enforcer.enable=true quarkus.keycloak.policy-enforcer.enforcement-mode=PERMISSIVE # Defines a global claim to be sent to Keycloak when evaluating permissions for any requesting coming to the application @@ -52,4 +53,22 @@ quarkus.keycloak.policy-enforcer.paths.8.enforcement-mode=DISABLED quarkus.keycloak.policy-enforcer.paths.9.name=Scope Permission Resource quarkus.keycloak.policy-enforcer.paths.9.path=/api/permission/scope +# Tenant + +quarkus.oidc.tenant.auth-server-url=${keycloak.url}/realms/quarkus +quarkus.oidc.tenant.client-id=quarkus-app +quarkus.oidc.tenant.credentials.secret=secret + +# Enable Policy Enforcement +quarkus.keycloak.tenant.policy-enforcer.enforcement-mode=PERMISSIVE + +# Defines a global claim to be sent to Keycloak when evaluating permissions for any requesting coming to the application +quarkus.keycloak.tenant.policy-enforcer.claim-information-point.claims.request-uri={request.relativePath} +quarkus.keycloak.tenant.policy-enforcer.claim-information-point.claims.request-method={request.method} + +# Defines a static claim that is only sent to Keycloak when evaluating permissions for a specific path +quarkus.keycloak.tenant.policy-enforcer.paths.1.name=Permission Resource Tenant +quarkus.keycloak.tenant.policy-enforcer.paths.1.path=/api-permission-tenant +quarkus.keycloak.tenant.policy-enforcer.paths.1.claim-information-point.claims.static-claim=static-claim + admin-url=${keycloak.url} \ No newline at end of file diff --git a/integration-tests/keycloak-authorization/src/test/java/io/quarkus/it/keycloak/KeycloakTestResource.java b/integration-tests/keycloak-authorization/src/test/java/io/quarkus/it/keycloak/KeycloakTestResource.java index 5e58e86a46524..687a5b45ae4f2 100644 --- a/integration-tests/keycloak-authorization/src/test/java/io/quarkus/it/keycloak/KeycloakTestResource.java +++ b/integration-tests/keycloak-authorization/src/test/java/io/quarkus/it/keycloak/KeycloakTestResource.java @@ -101,12 +101,23 @@ private static ClientRepresentation createClient(String clientId) { } private static void configurePermissionResourcePermission(ResourceServerRepresentation settings) { - PolicyRepresentation policy = createJSPolicy("Confidential Policy", "var identity = $evaluation.context.identity;\n" + + PolicyRepresentation policyConfidential = createJSPolicy("Confidential Policy", + "var identity = $evaluation.context.identity;\n" + + "\n" + + "if (identity.hasRealmRole(\"confidential\")) {\n" + + "$evaluation.grant();\n" + + "}", + settings); + createPermission(settings, createResource(settings, "Permission Resource", "/api/permission"), policyConfidential); + + PolicyRepresentation policyAdmin = createJSPolicy("Admin Policy", "var identity = $evaluation.context.identity;\n" + "\n" + - "if (identity.hasRealmRole(\"confidential\")) {\n" + + "if (identity.hasRealmRole(\"admin\")) {\n" + "$evaluation.grant();\n" + "}", settings); - createPermission(settings, createResource(settings, "Permission Resource", "/api/permission"), policy); + + createPermission(settings, createResource(settings, "Permission Resource Tenant", "/api-permission-tenant"), + policyAdmin); } private static void configureScopePermission(ResourceServerRepresentation settings) { diff --git a/integration-tests/keycloak-authorization/src/test/java/io/quarkus/it/keycloak/PolicyEnforcerTest.java b/integration-tests/keycloak-authorization/src/test/java/io/quarkus/it/keycloak/PolicyEnforcerTest.java index 3b2e02fcb232b..f3fb4354d79d0 100644 --- a/integration-tests/keycloak-authorization/src/test/java/io/quarkus/it/keycloak/PolicyEnforcerTest.java +++ b/integration-tests/keycloak-authorization/src/test/java/io/quarkus/it/keycloak/PolicyEnforcerTest.java @@ -29,6 +29,24 @@ public static void configureKeycloakRealm() throws IOException { public static void removeKeycloakRealm() { } + @Test + public void testUserHasRoleConfidentialTenant() { + RestAssured.given().auth().oauth2(getAccessToken("alice")) + .when().get("/api-permission-tenant") + .then() + .statusCode(403); + RestAssured.given().auth().oauth2(getAccessToken("jdoe")) + .when().get("/api-permission-tenant") + .then() + .statusCode(403); + RestAssured.given().auth().oauth2(getAccessToken("admin")) + .when().get("/api-permission-tenant") + .then() + .statusCode(200) + .and().body(Matchers.containsString("Permission Resource Tenant")); + ; + } + @Test public void testUserHasRoleConfidential() { RestAssured.given().auth().oauth2(getAccessToken("alice")) From bcd9bf4134ee04eb8257c5d7e6e680c27171ba84 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 May 2021 19:01:45 +0000 Subject: [PATCH 0057/2077] Bump mockito-core from 3.9.0 to 3.10.0 in /integration-tests/gradle Bumps [mockito-core](https://github.com/mockito/mockito) from 3.9.0 to 3.10.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.9.0...v3.10.0) Signed-off-by: dependabot[bot] --- integration-tests/gradle/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/gradle/build.gradle b/integration-tests/gradle/build.gradle index a3bff499f8d40..bcbcede4acd00 100644 --- a/integration-tests/gradle/build.gradle +++ b/integration-tests/gradle/build.gradle @@ -35,7 +35,7 @@ dependencies { testImplementation "io.quarkus:quarkus-devmode-test-utils:${version}" testImplementation "io.quarkus:quarkus-devtools-common:${version}" testImplementation "io.quarkus:io.quarkus.gradle.plugin:${version}" - testImplementation 'org.mockito:mockito-core:3.9.0' + testImplementation 'org.mockito:mockito-core:3.10.0' testImplementation 'org.assertj:assertj-core:3.19.0' testImplementation 'org.junit.jupiter:junit-jupiter:5.7.1' testImplementation 'org.awaitility:awaitility:4.1.0' From 20a50af33e3b6668cc127e3f246a6b1f27c89736 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 May 2021 19:23:39 +0000 Subject: [PATCH 0058/2077] Bump mariadb-java-client from 2.7.2 to 2.7.3 Bumps [mariadb-java-client](https://github.com/mariadb-corporation/mariadb-connector-j) from 2.7.2 to 2.7.3. - [Release notes](https://github.com/mariadb-corporation/mariadb-connector-j/releases) - [Changelog](https://github.com/mariadb-corporation/mariadb-connector-j/blob/master/CHANGELOG.md) - [Commits](https://github.com/mariadb-corporation/mariadb-connector-j/commits) Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 0e7aa4527a875..6eb7abcf88514 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -121,7 +121,7 @@ 2.3.2 1.4.197 42.2.20 - 2.7.2 + 2.7.3 8.0.25 7.2.2.jre8 21.1.0.0 From 0c3c5fe047b4dbaff581f7b13a78efdb353315bf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 May 2021 19:25:37 +0000 Subject: [PATCH 0059/2077] Bump mockito.version from 3.9.0 to 3.10.0 Bumps `mockito.version` from 3.9.0 to 3.10.0. Updates `mockito-core` from 3.9.0 to 3.10.0 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.9.0...v3.10.0) Updates `mockito-inline` from 3.9.0 to 3.10.0 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.9.0...v3.10.0) Updates `mockito-junit-jupiter` from 3.9.0 to 3.10.0 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.9.0...v3.10.0) Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- independent-projects/tools/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 0e7aa4527a875..def3ea897f5fc 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -183,7 +183,7 @@ 5.2.Final 2.1.SP1 2.40.0 - 3.9.0 + 3.10.0 5.3.1 4.8 1.1.4.Final diff --git a/independent-projects/tools/pom.xml b/independent-projects/tools/pom.xml index e792de79ac268..9f7c397862d9e 100644 --- a/independent-projects/tools/pom.xml +++ b/independent-projects/tools/pom.xml @@ -48,7 +48,7 @@ 1.20 3.4.1.Final 3.8.1 - 3.9.0 + 3.10.0 3.0.0-M5 1.6.8 999-SNAPSHOT From 974d7ad26fe72a6044bd9e916e19362489ad203b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 May 2021 20:05:31 +0000 Subject: [PATCH 0060/2077] Bump mockito-core from 3.9.0 to 3.10.0 in /devtools/gradle Bumps [mockito-core](https://github.com/mockito/mockito) from 3.9.0 to 3.10.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.9.0...v3.10.0) Signed-off-by: dependabot[bot] --- devtools/gradle/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devtools/gradle/build.gradle b/devtools/gradle/build.gradle index 289c8baaf65b2..de4176961da1e 100644 --- a/devtools/gradle/build.gradle +++ b/devtools/gradle/build.gradle @@ -35,7 +35,7 @@ dependencies { implementation "io.quarkus:quarkus-core-deployment:${version}" testImplementation "io.quarkus:quarkus-project-core-extension-codestarts:${version}" - testImplementation 'org.mockito:mockito-core:3.9.0' + testImplementation 'org.mockito:mockito-core:3.10.0' testImplementation 'org.assertj:assertj-core:3.19.0' testImplementation 'org.junit.jupiter:junit-jupiter:5.7.1' testImplementation 'org.awaitility:awaitility:4.1.0' From 49a3f1943ba6da47b3d67d5d0e15f5f6273a071d Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Wed, 12 May 2021 16:55:08 +1000 Subject: [PATCH 0061/2077] Fix issues with changes to test resources Previously these were not picked up and would not trigger test changes. --- bom/application/pom.xml | 7 + .../dev/HotDeploymentConfigFileBuildStep.java | 13 +- .../dev/RuntimeUpdatesProcessor.java | 120 ++++++++++-------- .../deployment/dev/testing/TestRunner.java | 6 + .../quarkus/dev/testing/TestWatchedFiles.java | 23 ++++ .../main/java/io/quarkus/maven/DevMojo.java | 1 + extensions/hibernate-orm/deployment/pom.xml | 16 +++ .../orm/deployment/HibernateOrmProcessor.java | 8 +- .../io/quarkus/hibernate/orm/HibernateET.java | 21 +++ .../orm/HibernateHotReloadTestCase.java | 55 +++++++- extensions/vertx-http/deployment/pom.xml | 11 ++ ...s.java => ContinuousTestingTestUtils.java} | 2 +- .../testrunner/QuarkusTestTypeTestCase.java | 4 +- ...tChangeTrackingWhenStartFailsTestCase.java | 10 +- .../testrunner/TestRunnerSmokeTestCase.java | 8 +- .../http/testrunner/UnitTestTypeTestCase.java | 4 +- .../brokenonly/TestBrokenOnlyTestCase.java | 14 +- .../includes/ExcludePatternTestCase.java | 14 +- .../includes/IncludePatternTestCase.java | 14 +- .../testrunner/tags/ExcludeTagsTestCase.java | 14 +- .../testrunner/tags/IncludeTagsTestCase.java | 14 +- .../io/quarkus/test/QuarkusDevModeTest.java | 18 ++- 22 files changed, 284 insertions(+), 113 deletions(-) create mode 100644 core/devmode-spi/src/main/java/io/quarkus/dev/testing/TestWatchedFiles.java create mode 100644 extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/HibernateET.java rename extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/{TestRunnerTestUtils.java => ContinuousTestingTestUtils.java} (97%) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index b80a9d3893a60..373f77c2fb96f 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -1465,6 +1465,13 @@ quarkus-vertx-http-deployment ${project.version} + + io.quarkus + quarkus-vertx-http-deployment + ${project.version} + test-jar + test + io.quarkus quarkus-vertx-web diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/HotDeploymentConfigFileBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/HotDeploymentConfigFileBuildStep.java index 203333a07f9b3..9e5fa01ad8238 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/HotDeploymentConfigFileBuildStep.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/HotDeploymentConfigFileBuildStep.java @@ -6,20 +6,27 @@ import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.builditem.HotDeploymentWatchedFileBuildItem; +import io.quarkus.deployment.builditem.LaunchModeBuildItem; import io.quarkus.deployment.builditem.ServiceStartBuildItem; +import io.quarkus.dev.testing.TestWatchedFiles; public class HotDeploymentConfigFileBuildStep { @BuildStep - ServiceStartBuildItem setupConfigFileHotDeployment(List files) { + ServiceStartBuildItem setupConfigFileHotDeployment(List files, + LaunchModeBuildItem launchModeBuildItem) { // TODO: this should really be an output of the RuntimeRunner RuntimeUpdatesProcessor processor = RuntimeUpdatesProcessor.INSTANCE; - if (processor != null) { + if (processor != null || launchModeBuildItem.isAuxiliaryApplication()) { Map watchedFilePaths = files.stream() .collect(Collectors.toMap(HotDeploymentWatchedFileBuildItem::getLocation, HotDeploymentWatchedFileBuildItem::isRestartNeeded, (isRestartNeeded1, isRestartNeeded2) -> isRestartNeeded1 || isRestartNeeded2)); - processor.setWatchedFilePaths(watchedFilePaths); + if (launchModeBuildItem.isAuxiliaryApplication()) { + TestWatchedFiles.setWatchedFilePaths(watchedFilePaths); + } else { + processor.setWatchedFilePaths(watchedFilePaths, false); + } } return null; } diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java index 23c99aafa6213..803df9312b093 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java @@ -20,6 +20,7 @@ import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.FileTime; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -81,9 +82,6 @@ public class RuntimeUpdatesProcessor implements HotReplacementContext, Closeable private final DevModeType devModeType; volatile Throwable compileProblem; - // file path -> isRestartNeeded - private volatile Map watchedFilePaths = Collections.emptyMap(); - private volatile Predicate disableInstrumentationForClassPredicate = new AlwaysFalsePredicate<>(); private volatile Predicate disableInstrumentationForIndexPredicate = new AlwaysFalsePredicate<>(); @@ -95,12 +93,6 @@ public class RuntimeUpdatesProcessor implements HotReplacementContext, Closeable private final TimestampSet test = new TimestampSet(); final Map sourceFileTimestamps = new ConcurrentHashMap<>(); - /** - * Resources that appear in both src and target, these will be removed if the src resource subsequently disappears. - * This map contains the paths in the target dir, one for each module, otherwise on a second module we will delete files - * from the first one - */ - private final Map> correspondingResources = new ConcurrentHashMap<>(); private final List preScanSteps = new CopyOnWriteArrayList<>(); private final List>> noRestartChangesConsumers = new CopyOnWriteArrayList<>(); private final List hotReplacementSetup = new ArrayList<>(); @@ -115,6 +107,13 @@ public class RuntimeUpdatesProcessor implements HotReplacementContext, Closeable */ private static volatile IndexView lastStartIndex; + /** + * Resources that appear in both src and target, these will be removed if the src resource subsequently disappears. + * This map contains the paths in the target dir, one for each module, otherwise on a second module we will delete files + * from the first one + */ + private final Map> correspondingResources = new ConcurrentHashMap<>(); + private final TestSupport testSupport; private volatile boolean firstTestScanComplete; private volatile Boolean instrumentationEnabled; @@ -248,9 +247,11 @@ private void periodicTestCompile() { try { ClassScanResult changedTestClassResult = compileTestClasses(); ClassScanResult changedApp = checkForChangedClasses(compiler, DevModeContext.ModuleInfo::getMain, false, test); - Set filesChanged = checkForFileChange(DevModeContext.ModuleInfo::getMain, test); - boolean configFileRestartNeeded = filesChanged.stream().map(watchedFilePaths::get) + Set filesChanges = new HashSet<>(checkForFileChange(s -> s.getTest().get(), test)); + filesChanges.addAll(checkForFileChange(DevModeContext.ModuleInfo::getMain, test)); + boolean configFileRestartNeeded = filesChanges.stream().map(test.watchedFilePaths::get) .anyMatch(Boolean.TRUE::equals); + ClassScanResult merged = ClassScanResult.merge(changedTestClassResult, changedApp); if (configFileRestartNeeded) { if (compileProblem != null) { @@ -369,7 +370,8 @@ public boolean doScan(boolean userInitiated, boolean force) throws IOException { main); Set filesChanged = checkForFileChange(DevModeContext.ModuleInfo::getMain, main); - boolean configFileRestartNeeded = filesChanged.stream().map(watchedFilePaths::get).anyMatch(Boolean.TRUE::equals); + boolean configFileRestartNeeded = filesChanged.stream().map(main.watchedFilePaths::get) + .anyMatch(Boolean.TRUE::equals); boolean instrumentationChange = false; if (ClassChangeAgent.getInstrumentation() != null && lastStartIndex != null && !configFileRestartNeeded && devModeType != DevModeType.REMOTE_LOCAL_SIDE) { @@ -561,7 +563,7 @@ ClassScanResult checkForChangedClasses(QuarkusCompiler compiler, changedSourceFiles = sourcesStream .parallel() .filter(p -> matchingHandledExtension(p).isPresent() - && sourceFileWasRecentModified(p, ignoreFirstScanChanges, timestampSet)) + && sourceFileWasRecentModified(p, ignoreFirstScanChanges)) .map(Path::toFile) //Needing a concurrent Set, not many standard options: .collect(Collectors.toCollection(ConcurrentSkipListSet::new)); @@ -695,7 +697,7 @@ Set checkForFileChange(Function ret = new HashSet<>(); for (DevModeContext.ModuleInfo module : context.getAllModules()) { - final Set moduleResources = correspondingResources.computeIfAbsent(module.getName(), + final Set moduleResources = correspondingResources.computeIfAbsent(cuf.apply(module), m -> Collections.newSetFromMap(new ConcurrentHashMap<>())); boolean doCopy = true; String rootPath = cuf.apply(module).getResourcePath(); @@ -759,13 +761,15 @@ Set checkForFileChange(Function existing) { + //existing can be null when running tests + //as there is both normal and test resources, but only one set of watched timestampts + if (existing != null && value > existing) { ret.add(path); log.infof("File change detected: %s", file); if (doCopy && !Files.isDirectory(file)) { @@ -795,8 +799,7 @@ Set checkForFileChange(Function watchedFilePaths) { - boolean includeTest = test.watchedFileTimestamps.isEmpty(); - this.watchedFilePaths = watchedFilePaths; - main.watchedFileTimestamps.clear(); + public RuntimeUpdatesProcessor setWatchedFilePaths(Map watchedFilePaths, boolean isTest) { + if (isTest) { + setWatchedFilePathsInternal(watchedFilePaths, test, s -> Arrays.asList(s.getTest().get(), s.getMain())); + } else { + main.watchedFileTimestamps.clear(); + setWatchedFilePathsInternal(watchedFilePaths, main, s -> Collections.singletonList(s.getMain())); + } + return this; + } + + private RuntimeUpdatesProcessor setWatchedFilePathsInternal(Map watchedFilePaths, + TimestampSet timestamps, Function> cuf) { + timestamps.watchedFilePaths = watchedFilePaths; Map extraWatchedFilePaths = new HashMap<>(); for (DevModeContext.ModuleInfo module : context.getAllModules()) { - String rootPath = module.getMain().getResourcePath(); + List compilationUnits = cuf.apply(module); + for (DevModeContext.CompilationUnit unit : compilationUnits) { + String rootPath = unit.getResourcePath(); - if (rootPath == null) { - rootPath = module.getMain().getClassesPath(); - } - if (rootPath == null) { - continue; - } - Path root = Paths.get(rootPath); - for (String path : watchedFilePaths.keySet()) { - Path config = root.resolve(path); - if (config.toFile().exists()) { - try { - FileTime lastModifiedTime = Files.getLastModifiedTime(config); - main.watchedFileTimestamps.put(config, lastModifiedTime.toMillis()); - if (includeTest) { - test.watchedFileTimestamps.put(config, lastModifiedTime.toMillis()); + if (rootPath == null) { + rootPath = unit.getClassesPath(); + } + if (rootPath == null) { + continue; + } + Path root = Paths.get(rootPath); + for (String path : watchedFilePaths.keySet()) { + Path config = root.resolve(path); + if (config.toFile().exists()) { + try { + FileTime lastModifiedTime = Files.getLastModifiedTime(config); + timestamps.watchedFileTimestamps.put(config, lastModifiedTime.toMillis()); + } catch (IOException e) { + throw new UncheckedIOException(e); } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } else { - main.watchedFileTimestamps.put(config, 0L); - Map extraWatchedFileTimestamps = expandGlobPattern(root, config); - main.watchedFileTimestamps.putAll(extraWatchedFileTimestamps); - for (Path extraPath : extraWatchedFileTimestamps.keySet()) { - extraWatchedFilePaths.put(root.relativize(extraPath).toString(), this.watchedFilePaths.get(path)); - } - if (includeTest) { - test.watchedFileTimestamps.put(config, 0L); + } else { + timestamps.watchedFileTimestamps.put(config, 0L); + Map extraWatchedFileTimestamps = expandGlobPattern(root, config); + timestamps.watchedFileTimestamps.putAll(extraWatchedFileTimestamps); + for (Path extraPath : extraWatchedFileTimestamps.keySet()) { + extraWatchedFilePaths.put(root.relativize(extraPath).toString(), + timestamps.watchedFilePaths.get(path)); + } + timestamps.watchedFileTimestamps.putAll(extraWatchedFileTimestamps); } - main.watchedFileTimestamps.putAll(extraWatchedFileTimestamps); } } } - this.watchedFilePaths.putAll(extraWatchedFilePaths); + timestamps.watchedFilePaths.putAll(extraWatchedFilePaths); return this; } @@ -970,11 +980,17 @@ static class TimestampSet { final Map watchedFileTimestamps = new ConcurrentHashMap<>(); final Map classFileChangeTimeStamps = new ConcurrentHashMap<>(); final Map classFilePathToSourceFilePath = new ConcurrentHashMap<>(); + // file path -> isRestartNeeded + private volatile Map watchedFilePaths = Collections.emptyMap(); public void merge(TimestampSet other) { watchedFileTimestamps.putAll(other.watchedFileTimestamps); classFileChangeTimeStamps.putAll(other.classFileChangeTimeStamps); classFilePathToSourceFilePath.putAll(other.classFilePathToSourceFilePath); + Map newVal = new HashMap<>(watchedFilePaths); + newVal.putAll(other.watchedFilePaths); + watchedFilePaths = newVal; + } } diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestRunner.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestRunner.java index 799f2d0d9e906..e9a29b16821fb 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestRunner.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestRunner.java @@ -25,6 +25,8 @@ import io.quarkus.bootstrap.app.CuratedApplication; import io.quarkus.deployment.dev.ClassScanResult; import io.quarkus.deployment.dev.DevModeContext; +import io.quarkus.deployment.dev.RuntimeUpdatesProcessor; +import io.quarkus.dev.testing.TestWatchedFiles; import io.quarkus.runtime.configuration.HyphenateEnumConverter; public class TestRunner { @@ -243,6 +245,10 @@ public void runComplete(TestRunResults results) { synchronized (this) { runner = null; } + Map watched = TestWatchedFiles.retrieveWatchedFilePaths(); + if (watched != null) { + RuntimeUpdatesProcessor.INSTANCE.setWatchedFilePaths(watched, true); + } if (disabled) { return; } diff --git a/core/devmode-spi/src/main/java/io/quarkus/dev/testing/TestWatchedFiles.java b/core/devmode-spi/src/main/java/io/quarkus/dev/testing/TestWatchedFiles.java new file mode 100644 index 0000000000000..8f67ac3b14c0d --- /dev/null +++ b/core/devmode-spi/src/main/java/io/quarkus/dev/testing/TestWatchedFiles.java @@ -0,0 +1,23 @@ +package io.quarkus.dev.testing; + +import java.util.Map; + +/** + * provides a way for a test run to tell the external application about watched paths. + * + * This could be a test specific application.properties or import.sql for example + */ +public class TestWatchedFiles { + + private static volatile Map watchedFilePaths; + + public static Map retrieveWatchedFilePaths() { + Map watchedFilePaths = TestWatchedFiles.watchedFilePaths; + TestWatchedFiles.watchedFilePaths = null; + return watchedFilePaths; + } + + public static void setWatchedFilePaths(Map watchedFilePaths) { + TestWatchedFiles.watchedFilePaths = watchedFilePaths; + } +} diff --git a/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java index 5bebabca2fe6d..12eec63882f5a 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java @@ -653,6 +653,7 @@ private void addProject(MavenDevModeLauncher.Builder builder, LocalProject local .setTestSourcePaths(testSourcePaths) .setTestClassesPath(testClassesPath) .setTestResourcePath(testResourcePath) + .setTestResourcesOutputPath(testClassesPath) .build(); if (root) { diff --git a/extensions/hibernate-orm/deployment/pom.xml b/extensions/hibernate-orm/deployment/pom.xml index 8e60cdce048ba..75cea02da2efe 100644 --- a/extensions/hibernate-orm/deployment/pom.xml +++ b/extensions/hibernate-orm/deployment/pom.xml @@ -67,6 +67,11 @@ quarkus-jdbc-h2-deployment test + + io.quarkus + quarkus-junit5 + test + io.rest-assured rest-assured @@ -82,6 +87,17 @@ quarkus-smallrye-metrics-deployment test + + io.quarkus + quarkus-vertx-http-deployment + test + test-jar + + + org.awaitility + awaitility + test + diff --git a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java index 542e43d4a2260..8854bfee3ed7e 100644 --- a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java +++ b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java @@ -861,11 +861,9 @@ private static void producePersistenceUnitDescriptorFromConfig( "Unable to find file referenced in '" + HIBERNATE_ORM_CONFIG_PREFIX + "sql-load-script=" + persistenceUnitConfig.sqlLoadScript.get() + "'. Remove property or add file to your path."); } - if (launchMode == LaunchMode.DEVELOPMENT) { - // in dev mode we want to make sure that we watch for changes to file even if it doesn't currently exist - // as a user could still add it after performing the initial configuration - hotDeploymentWatchedFiles.produce(new HotDeploymentWatchedFileBuildItem(importFile.get())); - } + // in dev mode we want to make sure that we watch for changes to file even if it doesn't currently exist + // as a user could still add it after performing the initial configuration + hotDeploymentWatchedFiles.produce(new HotDeploymentWatchedFileBuildItem(importFile.get())); } else { //Disable implicit loading of the default import script (import.sql) descriptor.getProperties().setProperty(AvailableSettings.HBM2DDL_IMPORT_FILES, ""); diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/HibernateET.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/HibernateET.java new file mode 100644 index 0000000000000..a8d612e2e79e1 --- /dev/null +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/HibernateET.java @@ -0,0 +1,21 @@ +package io.quarkus.hibernate.orm; + +import static org.hamcrest.Matchers.is; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; +import io.restassured.RestAssured; + +/** + * Test for continuous testing with hibernate + */ +@QuarkusTest +public class HibernateET { + + @Test + public void testImport() { + RestAssured.when().get("/my-entity/1").then().body(is("MyEntity:TEST ENTITY")); + } + +} diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/HibernateHotReloadTestCase.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/HibernateHotReloadTestCase.java index dfeb4982c4487..cb5b033cdafe8 100644 --- a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/HibernateHotReloadTestCase.java +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/HibernateHotReloadTestCase.java @@ -5,11 +5,15 @@ import java.util.function.Function; import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.StringAsset; import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import io.quarkus.test.QuarkusDevModeTest; +import io.quarkus.vertx.http.deployment.devmode.tests.TestStatus; +import io.quarkus.vertx.http.testrunner.ContinuousTestingTestUtils; import io.restassured.RestAssured; public class HibernateHotReloadTestCase { @@ -17,8 +21,18 @@ public class HibernateHotReloadTestCase { final static QuarkusDevModeTest TEST = new QuarkusDevModeTest() .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) .addClasses(MyEntity.class, MyEntityTestResource.class) - .addAsResource("application.properties") - .addAsResource("import.sql")); + .add(new StringAsset( + //TODO: we can't use devservices here because of issues with the class loading + //sometimes the external application.properties is picked up and sometimes it isn't + ContinuousTestingTestUtils.appProperties( + "quarkus.hibernate-orm.database.generation=drop-and-create", + "quarkus.datasource.jdbc.url=jdbc:h2:mem:test", + "%test.quarkus.datasource.jdbc.url=jdbc:h2:mem:testrunner")), + "application.properties") + .addAsResource("import.sql")) + .setTestArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addClass(HibernateET.class) + .addAsResource(new StringAsset("INSERT INTO MyEntity(id, name) VALUES(1, 'TEST ENTITY');"), "import.sql")); @Test public void testAddNewFieldToEntity() { @@ -65,6 +79,43 @@ public String apply(String s) { RestAssured.when().get("/other-entity/2").then().body(is("OtherEntity:import.sql load script entity")); } + @Test + public void testImportSqlWithContinuousTesting() { + + TestStatus ts = ContinuousTestingTestUtils.waitForFirstRunToComplete(); + Assertions.assertEquals(1L, ts.getLastRun()); + Assertions.assertEquals(0L, ts.getTestsFailed()); + Assertions.assertEquals(1L, ts.getTestsPassed()); + Assertions.assertEquals(0L, ts.getTestsSkipped()); + Assertions.assertEquals(-1L, ts.getRunning()); + + TEST.modifyTestResourceFile("import.sql", new Function() { + @Override + public String apply(String s) { + return s.replace("TEST ENTITY", "new entity"); + } + }); + ts = ContinuousTestingTestUtils.waitForRun(2); + Assertions.assertEquals(2L, ts.getLastRun()); + Assertions.assertEquals(1L, ts.getTestsFailed()); + Assertions.assertEquals(0L, ts.getTestsPassed()); + Assertions.assertEquals(0L, ts.getTestsSkipped()); + Assertions.assertEquals(-1L, ts.getRunning()); + + TEST.modifyTestSourceFile(HibernateET.class, new Function() { + @Override + public String apply(String s) { + return s.replace("TEST ENTITY", "new entity"); + } + }); + ts = ContinuousTestingTestUtils.waitForRun(3); + Assertions.assertEquals(3L, ts.getLastRun()); + Assertions.assertEquals(0L, ts.getTestsFailed()); + Assertions.assertEquals(1L, ts.getTestsPassed()); + Assertions.assertEquals(0L, ts.getTestsSkipped()); + Assertions.assertEquals(-1L, ts.getRunning()); + } + private void assertBodyIs(String expectedBody) { RestAssured.when().get("/my-entity/2").then().body(is(expectedBody)); } diff --git a/extensions/vertx-http/deployment/pom.xml b/extensions/vertx-http/deployment/pom.xml index 801fabbd1de0f..4a999a77eb4ad 100644 --- a/extensions/vertx-http/deployment/pom.xml +++ b/extensions/vertx-http/deployment/pom.xml @@ -103,6 +103,17 @@ + + org.apache.maven.plugins + maven-jar-plugin + + + + test-jar + + + + maven-compiler-plugin diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/TestRunnerTestUtils.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/ContinuousTestingTestUtils.java similarity index 97% rename from extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/TestRunnerTestUtils.java rename to extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/ContinuousTestingTestUtils.java index 2770080114718..66972d2aa7e7e 100644 --- a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/TestRunnerTestUtils.java +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/ContinuousTestingTestUtils.java @@ -13,7 +13,7 @@ /** * Utilities for testing the test runner itself */ -public class TestRunnerTestUtils { +public class ContinuousTestingTestUtils { public static TestStatus waitForFirstRunToComplete() { return waitForRun(1); diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/QuarkusTestTypeTestCase.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/QuarkusTestTypeTestCase.java index 62b495db3f426..e4b84dfecf957 100644 --- a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/QuarkusTestTypeTestCase.java +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/QuarkusTestTypeTestCase.java @@ -20,7 +20,7 @@ public class QuarkusTestTypeTestCase { @Override public JavaArchive get() { return ShrinkWrap.create(JavaArchive.class).addClass(HelloResource.class) - .add(new StringAsset(TestRunnerTestUtils.appProperties("quarkus.test.type=quarkus-test")), + .add(new StringAsset(ContinuousTestingTestUtils.appProperties("quarkus.test.type=quarkus-test")), "application.properties"); } }) @@ -33,7 +33,7 @@ public JavaArchive get() { @Test public void testQuarkusTestMode() throws InterruptedException { - TestStatus ts = TestRunnerTestUtils.waitForFirstRunToComplete(); + TestStatus ts = ContinuousTestingTestUtils.waitForFirstRunToComplete(); Assertions.assertEquals(1L, ts.getLastRun()); Assertions.assertEquals(1L, ts.getTestsFailed()); Assertions.assertEquals(1L, ts.getTestsPassed()); diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/TestChangeTrackingWhenStartFailsTestCase.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/TestChangeTrackingWhenStartFailsTestCase.java index 21714ab6c7424..2cf7be5815213 100644 --- a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/TestChangeTrackingWhenStartFailsTestCase.java +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/TestChangeTrackingWhenStartFailsTestCase.java @@ -21,7 +21,7 @@ public class TestChangeTrackingWhenStartFailsTestCase { @Override public JavaArchive get() { return ShrinkWrap.create(JavaArchive.class).addClasses(HelloResource.class, StartupFailer.class).add( - new StringAsset(TestRunnerTestUtils.appProperties()), + new StringAsset(ContinuousTestingTestUtils.appProperties()), "application.properties"); } }) @@ -34,7 +34,7 @@ public JavaArchive get() { @Test public void testChangeTrackingOnStartupFailure() throws InterruptedException { - TestStatus ts = TestRunnerTestUtils.waitForFirstRunToComplete(); + TestStatus ts = ContinuousTestingTestUtils.waitForFirstRunToComplete(); Assertions.assertEquals(1L, ts.getLastRun()); Assertions.assertEquals(2L, ts.getTestsFailed()); Assertions.assertEquals(2L, ts.getTestsPassed()); @@ -48,7 +48,7 @@ public String apply(String s) { return s.replace("//fail();", "fail();"); } }); - ts = TestRunnerTestUtils.waitForRun(2); + ts = ContinuousTestingTestUtils.waitForRun(2); Assertions.assertEquals(2L, ts.getLastRun()); Assertions.assertEquals(1L, ts.getTestsFailed()); Assertions.assertEquals(0L, ts.getTestsPassed()); @@ -61,7 +61,7 @@ public String apply(String s) { return s.replace("fail();", "fail();fail();"); } }); - ts = TestRunnerTestUtils.waitForRun(3); + ts = ContinuousTestingTestUtils.waitForRun(3); Assertions.assertEquals(3L, ts.getLastRun()); Assertions.assertEquals(1L, ts.getTestsFailed()); Assertions.assertEquals(0L, ts.getTestsPassed()); @@ -74,7 +74,7 @@ public String apply(String s) { return s.replace("fail();fail();", "//fail();"); } }); - ts = TestRunnerTestUtils.waitForRun(4); + ts = ContinuousTestingTestUtils.waitForRun(4); Assertions.assertEquals(4L, ts.getLastRun()); Assertions.assertEquals(2L, ts.getTestsFailed()); Assertions.assertEquals(2L, ts.getTestsPassed()); diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/TestRunnerSmokeTestCase.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/TestRunnerSmokeTestCase.java index 8bd46b08f533c..627fe449b514d 100644 --- a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/TestRunnerSmokeTestCase.java +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/TestRunnerSmokeTestCase.java @@ -24,7 +24,7 @@ public class TestRunnerSmokeTestCase { @Override public JavaArchive get() { return ShrinkWrap.create(JavaArchive.class).addClass(HelloResource.class) - .add(new StringAsset(TestRunnerTestUtils.appProperties()), + .add(new StringAsset(ContinuousTestingTestUtils.appProperties()), "application.properties"); } }) @@ -37,7 +37,7 @@ public JavaArchive get() { @Test public void checkTestsAreRun() throws InterruptedException { - TestStatus ts = TestRunnerTestUtils.waitForFirstRunToComplete(); + TestStatus ts = ContinuousTestingTestUtils.waitForFirstRunToComplete(); Assertions.assertEquals(1L, ts.getLastRun()); Assertions.assertEquals(2L, ts.getTestsFailed()); Assertions.assertEquals(1L, ts.getTestsPassed()); @@ -66,7 +66,7 @@ public String apply(String s) { return s.replace("//setup(router);", "setup(router);"); } }); - ts = TestRunnerTestUtils.waitForRun(2); + ts = ContinuousTestingTestUtils.waitForRun(2); Assertions.assertEquals(2L, ts.getLastRun()); Assertions.assertEquals(1L, ts.getTestsFailed()); Assertions.assertEquals(2L, ts.getTestsPassed()); @@ -81,7 +81,7 @@ public String apply(String s) { return s.replace("Hi", "hello"); } }); - ts = TestRunnerTestUtils.waitForRun(3); + ts = ContinuousTestingTestUtils.waitForRun(3); Assertions.assertEquals(3L, ts.getLastRun()); Assertions.assertEquals(0L, ts.getTestsFailed()); Assertions.assertEquals(1L, ts.getTestsPassed()); diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/UnitTestTypeTestCase.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/UnitTestTypeTestCase.java index 36f389e542079..b607a6c6067a9 100644 --- a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/UnitTestTypeTestCase.java +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/UnitTestTypeTestCase.java @@ -20,7 +20,7 @@ public class UnitTestTypeTestCase { @Override public JavaArchive get() { return ShrinkWrap.create(JavaArchive.class).addClass(HelloResource.class) - .add(new StringAsset(TestRunnerTestUtils.appProperties("quarkus.test.type=unit")), + .add(new StringAsset(ContinuousTestingTestUtils.appProperties("quarkus.test.type=unit")), "application.properties"); } }) @@ -33,7 +33,7 @@ public JavaArchive get() { @Test public void testUnitMode() throws InterruptedException { - TestStatus ts = TestRunnerTestUtils.waitForFirstRunToComplete(); + TestStatus ts = ContinuousTestingTestUtils.waitForFirstRunToComplete(); Assertions.assertEquals(1L, ts.getLastRun()); Assertions.assertEquals(1L, ts.getTestsFailed()); Assertions.assertEquals(0L, ts.getTestsPassed()); diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/brokenonly/TestBrokenOnlyTestCase.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/brokenonly/TestBrokenOnlyTestCase.java index 91f26a8b37a43..d5814be494580 100644 --- a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/brokenonly/TestBrokenOnlyTestCase.java +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/brokenonly/TestBrokenOnlyTestCase.java @@ -12,7 +12,7 @@ import io.quarkus.test.QuarkusDevModeTest; import io.quarkus.vertx.http.deployment.devmode.tests.TestStatus; -import io.quarkus.vertx.http.testrunner.TestRunnerTestUtils; +import io.quarkus.vertx.http.testrunner.ContinuousTestingTestUtils; import io.restassured.RestAssured; public class TestBrokenOnlyTestCase { @@ -23,7 +23,7 @@ public class TestBrokenOnlyTestCase { @Override public JavaArchive get() { return ShrinkWrap.create(JavaArchive.class).addClass(BrokenOnlyResource.class) - .add(new StringAsset(TestRunnerTestUtils.appProperties()), + .add(new StringAsset(ContinuousTestingTestUtils.appProperties()), "application.properties"); } }) @@ -36,7 +36,7 @@ public JavaArchive get() { @Test public void testBrokenOnlyMode() throws InterruptedException { - TestStatus ts = TestRunnerTestUtils.waitForFirstRunToComplete(); + TestStatus ts = ContinuousTestingTestUtils.waitForFirstRunToComplete(); Assertions.assertEquals(1L, ts.getLastRun()); Assertions.assertEquals(1L, ts.getTestsFailed()); Assertions.assertEquals(1L, ts.getTestsPassed()); @@ -52,7 +52,7 @@ public String apply(String s) { return s.replace("@QuarkusTest", "@QuarkusTest //noop change"); } }); - ts = TestRunnerTestUtils.waitForRun(2); + ts = ContinuousTestingTestUtils.waitForRun(2); Assertions.assertEquals(2L, ts.getLastRun()); Assertions.assertEquals(1L, ts.getTestsFailed()); Assertions.assertEquals(0L, ts.getTestsPassed()); //passing test should not have been run @@ -65,7 +65,7 @@ public String apply(String s) { return s.replace("//setup(router);", "setup(router);"); } }); - ts = TestRunnerTestUtils.waitForRun(3); + ts = ContinuousTestingTestUtils.waitForRun(3); Assertions.assertEquals(3L, ts.getLastRun()); Assertions.assertEquals(0L, ts.getTestsFailed()); Assertions.assertEquals(1L, ts.getTestsPassed()); @@ -79,7 +79,7 @@ public String apply(String s) { return s.replace("//failannotation", "@Test"); } }); - ts = TestRunnerTestUtils.waitForRun(4); + ts = ContinuousTestingTestUtils.waitForRun(4); Assertions.assertEquals(4L, ts.getLastRun()); Assertions.assertEquals(1L, ts.getTestsFailed()); Assertions.assertEquals(0L, ts.getTestsPassed()); @@ -93,7 +93,7 @@ public String apply(String s) { return s.replace("Assertions.fail();", "//noop"); } }); - ts = TestRunnerTestUtils.waitForRun(5); + ts = ContinuousTestingTestUtils.waitForRun(5); Assertions.assertEquals(5L, ts.getLastRun()); Assertions.assertEquals(0L, ts.getTestsFailed()); Assertions.assertEquals(1L, ts.getTestsPassed()); diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/includes/ExcludePatternTestCase.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/includes/ExcludePatternTestCase.java index 599f4717635ed..bb734ba7bf7ab 100644 --- a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/includes/ExcludePatternTestCase.java +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/includes/ExcludePatternTestCase.java @@ -12,8 +12,8 @@ import io.quarkus.test.QuarkusDevModeTest; import io.quarkus.vertx.http.deployment.devmode.tests.TestStatus; +import io.quarkus.vertx.http.testrunner.ContinuousTestingTestUtils; import io.quarkus.vertx.http.testrunner.HelloResource; -import io.quarkus.vertx.http.testrunner.TestRunnerTestUtils; public class ExcludePatternTestCase { @@ -24,7 +24,7 @@ public class ExcludePatternTestCase { public JavaArchive get() { return ShrinkWrap.create(JavaArchive.class).addClass(HelloResource.class) .add(new StringAsset( - TestRunnerTestUtils.appProperties("quarkus.test.exclude-pattern=.*BarET")), + ContinuousTestingTestUtils.appProperties("quarkus.test.exclude-pattern=.*BarET")), "application.properties"); } }) @@ -37,7 +37,7 @@ public JavaArchive get() { @Test public void checkTestsAreRun() throws InterruptedException { - TestStatus ts = TestRunnerTestUtils.waitForFirstRunToComplete(); + TestStatus ts = ContinuousTestingTestUtils.waitForFirstRunToComplete(); Assertions.assertEquals(1L, ts.getLastRun()); Assertions.assertEquals(0L, ts.getTestsFailed()); Assertions.assertEquals(1L, ts.getTestsPassed()); @@ -47,10 +47,10 @@ public void checkTestsAreRun() throws InterruptedException { test.modifyResourceFile("application.properties", new Function() { @Override public String apply(String s) { - return TestRunnerTestUtils.appProperties("quarkus.test.exclude-pattern=missing"); + return ContinuousTestingTestUtils.appProperties("quarkus.test.exclude-pattern=missing"); } }); - ts = TestRunnerTestUtils.waitForRun(2); + ts = ContinuousTestingTestUtils.waitForRun(2); Assertions.assertEquals(2L, ts.getLastRun()); Assertions.assertEquals(0L, ts.getTestsFailed()); Assertions.assertEquals(2L, ts.getTestsPassed()); @@ -60,10 +60,10 @@ public String apply(String s) { test.modifyResourceFile("application.properties", new Function() { @Override public String apply(String s) { - return TestRunnerTestUtils.appProperties(); + return ContinuousTestingTestUtils.appProperties(); } }); - ts = TestRunnerTestUtils.waitForRun(3); + ts = ContinuousTestingTestUtils.waitForRun(3); Assertions.assertEquals(3L, ts.getLastRun()); Assertions.assertEquals(0L, ts.getTestsFailed()); Assertions.assertEquals(2L, ts.getTestsPassed()); diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/includes/IncludePatternTestCase.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/includes/IncludePatternTestCase.java index 6074522262b6f..36c3093f320b8 100644 --- a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/includes/IncludePatternTestCase.java +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/includes/IncludePatternTestCase.java @@ -12,8 +12,8 @@ import io.quarkus.test.QuarkusDevModeTest; import io.quarkus.vertx.http.deployment.devmode.tests.TestStatus; +import io.quarkus.vertx.http.testrunner.ContinuousTestingTestUtils; import io.quarkus.vertx.http.testrunner.HelloResource; -import io.quarkus.vertx.http.testrunner.TestRunnerTestUtils; public class IncludePatternTestCase { @@ -24,7 +24,7 @@ public class IncludePatternTestCase { public JavaArchive get() { return ShrinkWrap.create(JavaArchive.class).addClass(HelloResource.class) .add(new StringAsset( - TestRunnerTestUtils.appProperties("quarkus.test.include-pattern=.*BarET")), + ContinuousTestingTestUtils.appProperties("quarkus.test.include-pattern=.*BarET")), "application.properties"); } }) @@ -37,7 +37,7 @@ public JavaArchive get() { @Test public void checkTestsAreRun() throws InterruptedException { - TestStatus ts = TestRunnerTestUtils.waitForFirstRunToComplete(); + TestStatus ts = ContinuousTestingTestUtils.waitForFirstRunToComplete(); Assertions.assertEquals(1L, ts.getLastRun()); Assertions.assertEquals(0L, ts.getTestsFailed()); Assertions.assertEquals(1L, ts.getTestsPassed()); @@ -47,10 +47,10 @@ public void checkTestsAreRun() throws InterruptedException { test.modifyResourceFile("application.properties", new Function() { @Override public String apply(String s) { - return TestRunnerTestUtils.appProperties("quarkus.test.include-pattern=io\\.quarkus.*"); + return ContinuousTestingTestUtils.appProperties("quarkus.test.include-pattern=io\\.quarkus.*"); } }); - ts = TestRunnerTestUtils.waitForRun(2); + ts = ContinuousTestingTestUtils.waitForRun(2); Assertions.assertEquals(2L, ts.getLastRun()); Assertions.assertEquals(0L, ts.getTestsFailed()); Assertions.assertEquals(2L, ts.getTestsPassed()); @@ -60,10 +60,10 @@ public String apply(String s) { test.modifyResourceFile("application.properties", new Function() { @Override public String apply(String s) { - return TestRunnerTestUtils.appProperties(); + return ContinuousTestingTestUtils.appProperties(); } }); - ts = TestRunnerTestUtils.waitForRun(3); + ts = ContinuousTestingTestUtils.waitForRun(3); Assertions.assertEquals(3L, ts.getLastRun()); Assertions.assertEquals(0L, ts.getTestsFailed()); Assertions.assertEquals(2L, ts.getTestsPassed()); diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/tags/ExcludeTagsTestCase.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/tags/ExcludeTagsTestCase.java index 1407d0c91fc1f..b99135a7c1e33 100644 --- a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/tags/ExcludeTagsTestCase.java +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/tags/ExcludeTagsTestCase.java @@ -12,8 +12,8 @@ import io.quarkus.test.QuarkusDevModeTest; import io.quarkus.vertx.http.deployment.devmode.tests.TestStatus; +import io.quarkus.vertx.http.testrunner.ContinuousTestingTestUtils; import io.quarkus.vertx.http.testrunner.HelloResource; -import io.quarkus.vertx.http.testrunner.TestRunnerTestUtils; public class ExcludeTagsTestCase { @@ -23,7 +23,7 @@ public class ExcludeTagsTestCase { @Override public JavaArchive get() { return ShrinkWrap.create(JavaArchive.class).addClass(HelloResource.class) - .add(new StringAsset(TestRunnerTestUtils.appProperties("quarkus.test.exclude-tags=a")), + .add(new StringAsset(ContinuousTestingTestUtils.appProperties("quarkus.test.exclude-tags=a")), "application.properties"); } }) @@ -36,7 +36,7 @@ public JavaArchive get() { @Test public void checkTestsAreRun() throws InterruptedException { - TestStatus ts = TestRunnerTestUtils.waitForFirstRunToComplete(); + TestStatus ts = ContinuousTestingTestUtils.waitForFirstRunToComplete(); Assertions.assertEquals(1L, ts.getLastRun()); Assertions.assertEquals(0L, ts.getTestsFailed()); Assertions.assertEquals(3L, ts.getTestsPassed()); @@ -46,13 +46,13 @@ public void checkTestsAreRun() throws InterruptedException { test.modifyResourceFile("application.properties", new Function() { @Override public String apply(String s) { - return TestRunnerTestUtils.appProperties("quarkus.test.exclude-tags=c"); + return ContinuousTestingTestUtils.appProperties("quarkus.test.exclude-tags=c"); } }); //we sleep here to make sure it is not the dev mode restart that is //causing the config to be updated Thread.sleep(1000); - ts = TestRunnerTestUtils.waitForRun(2); + ts = ContinuousTestingTestUtils.waitForRun(2); Assertions.assertEquals(2L, ts.getLastRun()); Assertions.assertEquals(0L, ts.getTestsFailed()); Assertions.assertEquals(4L, ts.getTestsPassed()); @@ -62,10 +62,10 @@ public String apply(String s) { test.modifyResourceFile("application.properties", new Function() { @Override public String apply(String s) { - return TestRunnerTestUtils.appProperties(); + return ContinuousTestingTestUtils.appProperties(); } }); - ts = TestRunnerTestUtils.waitForRun(3); + ts = ContinuousTestingTestUtils.waitForRun(3); Assertions.assertEquals(3L, ts.getLastRun()); Assertions.assertEquals(0L, ts.getTestsFailed()); Assertions.assertEquals(5L, ts.getTestsPassed()); diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/tags/IncludeTagsTestCase.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/tags/IncludeTagsTestCase.java index f9b78753dc102..a192f696e1b29 100644 --- a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/tags/IncludeTagsTestCase.java +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/tags/IncludeTagsTestCase.java @@ -12,8 +12,8 @@ import io.quarkus.test.QuarkusDevModeTest; import io.quarkus.vertx.http.deployment.devmode.tests.TestStatus; +import io.quarkus.vertx.http.testrunner.ContinuousTestingTestUtils; import io.quarkus.vertx.http.testrunner.HelloResource; -import io.quarkus.vertx.http.testrunner.TestRunnerTestUtils; public class IncludeTagsTestCase { @@ -23,7 +23,7 @@ public class IncludeTagsTestCase { @Override public JavaArchive get() { return ShrinkWrap.create(JavaArchive.class).addClass(HelloResource.class) - .add(new StringAsset(TestRunnerTestUtils.appProperties("quarkus.test.include-tags=a")), + .add(new StringAsset(ContinuousTestingTestUtils.appProperties("quarkus.test.include-tags=a")), "application.properties"); } }) @@ -36,7 +36,7 @@ public JavaArchive get() { @Test public void checkTestsAreRun() throws InterruptedException { - TestStatus ts = TestRunnerTestUtils.waitForFirstRunToComplete(); + TestStatus ts = ContinuousTestingTestUtils.waitForFirstRunToComplete(); Assertions.assertEquals(1L, ts.getLastRun()); Assertions.assertEquals(0L, ts.getTestsFailed()); Assertions.assertEquals(2L, ts.getTestsPassed()); @@ -46,10 +46,10 @@ public void checkTestsAreRun() throws InterruptedException { test.modifyResourceFile("application.properties", new Function() { @Override public String apply(String s) { - return TestRunnerTestUtils.appProperties("quarkus.test.include-tags=c"); + return ContinuousTestingTestUtils.appProperties("quarkus.test.include-tags=c"); } }); - ts = TestRunnerTestUtils.waitForRun(2); + ts = ContinuousTestingTestUtils.waitForRun(2); Assertions.assertEquals(2L, ts.getLastRun()); Assertions.assertEquals(0L, ts.getTestsFailed()); Assertions.assertEquals(1L, ts.getTestsPassed()); @@ -59,10 +59,10 @@ public String apply(String s) { test.modifyResourceFile("application.properties", new Function() { @Override public String apply(String s) { - return TestRunnerTestUtils.appProperties(); + return ContinuousTestingTestUtils.appProperties(); } }); - ts = TestRunnerTestUtils.waitForRun(3); + ts = ContinuousTestingTestUtils.waitForRun(3); Assertions.assertEquals(3L, ts.getLastRun()); Assertions.assertEquals(0L, ts.getTestsFailed()); Assertions.assertEquals(5L, ts.getTestsPassed()); diff --git a/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusDevModeTest.java b/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusDevModeTest.java index 343349e0daf06..cf1237660f5e3 100644 --- a/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusDevModeTest.java +++ b/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusDevModeTest.java @@ -386,7 +386,8 @@ private DevModeContext exportArchive(Path deploymentDir, Path testSourceDir, Pat moduleBuilder .setTestSourcePaths(Collections.singleton(deploymentTestSourcePath.toAbsolutePath().toString())) .setTestClassesPath(testClasses.toAbsolutePath().toString()) - .setTestResourcePath(deploymentTestResourcePath.toAbsolutePath().toString()); + .setTestResourcePath(deploymentTestResourcePath.toAbsolutePath().toString()) + .setTestResourcesOutputPath(testClasses.toAbsolutePath().toString()); } context.setApplicationRoot( @@ -670,8 +671,12 @@ private long modTime(Path path) { * the deployment resources directory */ public void modifyResourceFile(String path, Function mutator) { + Path resourcePath = deploymentResourcePath.resolve(path); + internalModifyResource(mutator, resourcePath); + } + + private void internalModifyResource(Function mutator, Path resourcePath) { try { - Path resourcePath = deploymentResourcePath.resolve(path); long old = modTime(resourcePath); byte[] data; try (InputStream in = Files.newInputStream(resourcePath)) { @@ -688,6 +693,15 @@ public void modifyResourceFile(String path, Function mutator) { } } + /** + * Adds or overwrites a resource file with the given data. The path is an absolute path into to + * the deployment resources directory + */ + public void modifyTestResourceFile(String path, Function mutator) { + Path resourcePath = deploymentTestResourcePath.resolve(path); + internalModifyResource(mutator, resourcePath); + } + /** * Adds or overwrites a resource file with the given data. The path is an absolute path into to * the deployment resources directory From 0a2f136c00fdf00b32dcb686b7da31c1c1fc5b40 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Wed, 12 May 2021 19:04:41 +0300 Subject: [PATCH 0062/2077] Save a small amount of allocations during init This is done by using the known size of the List parameters of recorders --- .../recording/BytecodeRecorderImpl.java | 70 +++++++++++-------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java b/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java index aea47243a02fc..6d2107a8c2978 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java @@ -1103,8 +1103,8 @@ private DeferredParameter loadComplexObject(Object param, Map setupSteps = new ArrayList<>(); - List ctorSetupSteps = new ArrayList<>(); + List setupSteps = new ArrayList<>(); + List ctorSetupSteps = new ArrayList<>(); boolean relaxedOk = false; if (param instanceof Collection) { @@ -1113,7 +1113,7 @@ private DeferredParameter loadComplexObject(Object param, Map context.loadDeferred(m)) .toArray(ResultHandle[]::new)); } else { - try { - param.getClass().getDeclaredConstructor(); - out = method.newInstance(ofConstructor(param.getClass())); - } catch (NoSuchMethodException e) { - //fallback for collection types, such as unmodifiableMap - if (SortedMap.class.isAssignableFrom(expectedType)) { - out = method.newInstance(ofConstructor(TreeMap.class)); - } else if (Map.class.isAssignableFrom(expectedType)) { - out = method.newInstance(ofConstructor(LinkedHashMap.class)); - } else if (List.class.isAssignableFrom(expectedType)) { + if (List.class.isAssignableFrom(param.getClass())) { + // list is a common special case, so let's handle it + List listParam = (List) param; + if (listParam.isEmpty()) { out = method.newInstance(ofConstructor(ArrayList.class)); - } else if (SortedSet.class.isAssignableFrom(expectedType)) { - out = method.newInstance(ofConstructor(TreeSet.class)); - } else if (Set.class.isAssignableFrom(expectedType)) { - out = method.newInstance(ofConstructor(LinkedHashSet.class)); } else { - throw new RuntimeException("Unable to serialize objects of type " + param.getClass() - + " to bytecode as it has no default constructor"); + out = method.newInstance(ofConstructor(ArrayList.class, int.class), method.load(listParam.size())); + } + } else { + try { + param.getClass().getDeclaredConstructor(); + out = method.newInstance(ofConstructor(param.getClass())); + } catch (NoSuchMethodException e) { + //fallback for collection types, such as unmodifiableMap + if (SortedMap.class.isAssignableFrom(expectedType)) { + out = method.newInstance(ofConstructor(TreeMap.class)); + } else if (Map.class.isAssignableFrom(expectedType)) { + out = method.newInstance(ofConstructor(LinkedHashMap.class)); + } else if (List.class.isAssignableFrom(expectedType)) { + out = method.newInstance(ofConstructor(ArrayList.class)); + } else if (SortedSet.class.isAssignableFrom(expectedType)) { + out = method.newInstance(ofConstructor(TreeSet.class)); + } else if (Set.class.isAssignableFrom(expectedType)) { + out = method.newInstance(ofConstructor(LinkedHashSet.class)); + } else { + throw new RuntimeException("Unable to serialize objects of type " + param.getClass() + + " to bytecode as it has no default constructor"); + } } } } @@ -1477,15 +1487,15 @@ ResultHandle createValue(MethodContext context, MethodCreator method, ResultHand void doPrepare(MethodContext context) { //this is where the object construction happens //first create the actial object - for (SerialzationStep i : ctorSetupSteps) { + for (SerializationStep i : ctorSetupSteps) { i.prepare(context); } objectValue.prepare(context); - for (SerialzationStep i : setupSteps) { + for (SerializationStep i : setupSteps) { //then prepare the steps (i.e. creating the values to be placed into this object) i.prepare(context); } - for (SerialzationStep i : setupSteps) { + for (SerializationStep i : setupSteps) { //now actually run the steps (i.e. actually stick the values into the object) context.writeInstruction(new InstructionGroup() { @Override @@ -1792,7 +1802,7 @@ final ResultHandle doLoad(MethodContext context, MethodCreator method, ResultHan /** * A step that must be executed to serialize a complex object */ - interface SerialzationStep { + interface SerializationStep { void handle(MethodContext context, MethodCreator method, DeferredArrayStoreParameter out); From b435def31d99acf1a362482591be70b5eb3fa014 Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Thu, 13 May 2021 11:42:40 +1000 Subject: [PATCH 0063/2077] More test CL changes This allows non-class resources to be loaded parent first to work around ClassLoading issues in libraries. Fixes #17175 --- .../bootstrap/app/CuratedApplication.java | 68 ++++++++++++++++++- .../classloading/QuarkusClassLoader.java | 10 +++ .../src/main/resources/wrong-classloading.txt | 1 + ...correctClassloadingWorkaroundTestCase.java | 25 +++++++ .../src/main/resources/application.properties | 3 - .../io/quarkus/it/shared/SharedResource.java | 15 ++++ 6 files changed, 117 insertions(+), 5 deletions(-) create mode 100644 integration-tests/main/src/main/resources/wrong-classloading.txt create mode 100644 integration-tests/main/src/test/java/io/quarkus/it/main/IncorrectClassloadingWorkaroundTestCase.java delete mode 100644 integration-tests/picocli-native/src/main/resources/application.properties diff --git a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/app/CuratedApplication.java b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/app/CuratedApplication.java index 567117ec9057c..355e6af8f2823 100644 --- a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/app/CuratedApplication.java +++ b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/app/CuratedApplication.java @@ -2,14 +2,17 @@ import io.quarkus.bootstrap.BootstrapConstants; import io.quarkus.bootstrap.classloading.ClassPathElement; +import io.quarkus.bootstrap.classloading.ClassPathResource; import io.quarkus.bootstrap.classloading.MemoryClassPathElement; import io.quarkus.bootstrap.classloading.QuarkusClassLoader; import io.quarkus.bootstrap.model.AppArtifact; import io.quarkus.bootstrap.model.AppArtifactKey; import io.quarkus.bootstrap.model.AppDependency; import io.quarkus.bootstrap.model.AppModel; +import java.io.IOException; import java.io.Serializable; import java.nio.file.Path; +import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -20,6 +23,8 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; +import java.util.jar.Manifest; +import java.util.stream.Collectors; /** * The result of the curate step that is done by QuarkusBootstrap. @@ -218,7 +223,7 @@ public synchronized QuarkusClassLoader getBaseRuntimeClassLoader() { } } else { for (Path root : quarkusBootstrap.getApplicationRoot()) { - builder.addBannedElement(ClassPathElement.fromPath(root)); + builder.addBannedElement(new ClassFilteredBannedElement(ClassPathElement.fromPath(root))); } } @@ -232,7 +237,7 @@ public synchronized QuarkusClassLoader getBaseRuntimeClassLoader() { } else { for (Path root : i.getArchivePath()) { hotReloadPaths.add(root); - builder.addBannedElement(ClassPathElement.fromPath(root)); + builder.addBannedElement(new ClassFilteredBannedElement(ClassPathElement.fromPath(root))); } } } @@ -331,4 +336,63 @@ public void close() { baseRuntimeClassLoader.close(); } } + + /** + * TODO: Fix everything in the universe to do loading properly + * + * This class exists because a lot of libraries do getClass().getClassLoader.getResource() + * instead of using the context class loader, which breaks tests as these resources are present in the + * top CL and not the base CL that is used to load libraries. + * + * This yucky yucky hack works around this, by allowing non-class files to be loaded parent first, so they + * will be loaded from the application ClassLoader. + * + * Note that the underlying reason for this 'banned element' existing in the first place + * is because other libraries do Class Loading wrong in different ways, and attempt to load + * from the TCCL as a fallback instead of as the first priority, so we need to have the banned element + * to prevent a load from the application ClassLoader (which won't work). + * + */ + static class ClassFilteredBannedElement implements ClassPathElement { + + private final ClassPathElement delegate; + + ClassFilteredBannedElement(ClassPathElement delegate) { + this.delegate = delegate; + } + + @Override + public Path getRoot() { + return delegate.getRoot(); + } + + @Override + public ClassPathResource getResource(String name) { + if (!name.endsWith(".class")) { + return null; + } + return delegate.getResource(name); + } + + @Override + public Set getProvidedResources() { + return delegate.getProvidedResources().stream().filter(s -> s.endsWith(".class")).collect(Collectors.toSet()); + } + + @Override + public ProtectionDomain getProtectionDomain(ClassLoader classLoader) { + return delegate.getProtectionDomain(classLoader); + } + + @Override + public Manifest getManifest() { + return delegate.getManifest(); + } + + @Override + public void close() throws IOException { + delegate.close(); + } + } + } diff --git a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/classloading/QuarkusClassLoader.java b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/classloading/QuarkusClassLoader.java index a0ab908b9b243..c9a88c539fe13 100644 --- a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/classloading/QuarkusClassLoader.java +++ b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/classloading/QuarkusClassLoader.java @@ -567,6 +567,16 @@ public void close() { log.error("Failed to close " + element, e); } } + for (ClassPathElement element : bannedElements) { + //note that this is a 'soft' close + //all resources are closed, however the CL can still be used + //but after close no resources will be held past the scope of an operation + try (ClassPathElement ignored = element) { + //the close() operation is implied by the try-with syntax + } catch (Exception e) { + log.error("Failed to close " + element, e); + } + } ResourceBundle.clearCache(this); } diff --git a/integration-tests/main/src/main/resources/wrong-classloading.txt b/integration-tests/main/src/main/resources/wrong-classloading.txt new file mode 100644 index 0000000000000..50a5cb6b1b485 --- /dev/null +++ b/integration-tests/main/src/main/resources/wrong-classloading.txt @@ -0,0 +1 @@ +Wrong Classloading \ No newline at end of file diff --git a/integration-tests/main/src/test/java/io/quarkus/it/main/IncorrectClassloadingWorkaroundTestCase.java b/integration-tests/main/src/test/java/io/quarkus/it/main/IncorrectClassloadingWorkaroundTestCase.java new file mode 100644 index 0000000000000..03d5dbc561e86 --- /dev/null +++ b/integration-tests/main/src/test/java/io/quarkus/it/main/IncorrectClassloadingWorkaroundTestCase.java @@ -0,0 +1,25 @@ +package io.quarkus.it.main; + +import static org.hamcrest.Matchers.is; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; +import io.restassured.RestAssured; + +//https://github.com/quarkusio/quarkus/issues/17175 +@QuarkusTest +public class IncorrectClassloadingWorkaroundTestCase { + + /** + * libraries should load from the Thread Context Class Loader + * we test that even if libraries do the wrong thing our workaround still works + * without the need to force flat Class-Path + */ + @Test + public void testClassloadingStillWorksWhenLibrariesLoadFromWrongCL() { + RestAssured.when().get("/shared/classloading").then() + .body(is("Wrong Classloading")); + } + +} diff --git a/integration-tests/picocli-native/src/main/resources/application.properties b/integration-tests/picocli-native/src/main/resources/application.properties deleted file mode 100644 index fb60b142eb2e6..0000000000000 --- a/integration-tests/picocli-native/src/main/resources/application.properties +++ /dev/null @@ -1,3 +0,0 @@ - -#picocli attempts to load resource bundles from its own CL rather than the TCCL -quarkus.test.flat-class-path=true \ No newline at end of file diff --git a/integration-tests/shared-library/src/main/java/io/quarkus/it/shared/SharedResource.java b/integration-tests/shared-library/src/main/java/io/quarkus/it/shared/SharedResource.java index ffc88873eeecf..0dcf3ce84f797 100644 --- a/integration-tests/shared-library/src/main/java/io/quarkus/it/shared/SharedResource.java +++ b/integration-tests/shared-library/src/main/java/io/quarkus/it/shared/SharedResource.java @@ -1,5 +1,8 @@ package io.quarkus.it.shared; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + import javax.ws.rs.GET; import javax.ws.rs.Path; @@ -10,4 +13,16 @@ public class SharedResource { public String shared() { return "Shared Resource"; } + + //https://github.com/quarkusio/quarkus/issues/17175 + @GET + @Path("/classloading") + public String loadFromWrongClassLoader() throws Exception { + //this is wrong, libraries should load from the Thread Context Class Loader + //we test that even if libraries do the wrong thing our workaround still works + //without the need to force flat Class-Path + try (InputStream is = getClass().getClassLoader().getResourceAsStream("wrong-classloading.txt")) { + return new String(is.readAllBytes(), StandardCharsets.UTF_8); + } + } } From 97d09bbd26efa6c33d7eda9f745981011e3a884d Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Thu, 13 May 2021 17:57:32 +1000 Subject: [PATCH 0064/2077] Improve continuous testing status message The message is now the same for passed/failed (but a different color). It show total passed/failed, and the results of the last run. --- .../dev/testing/JunitTestRunner.java | 19 +------ .../dev/testing/TestConsoleHandler.java | 25 ++++----- .../dev/testing/TestRunResults.java | 56 +++++++++++++++---- .../ContinuousTestingWebSocketListener.java | 10 ++-- .../devmode/tests/TestsProcessor.java | 8 +-- 5 files changed, 65 insertions(+), 53 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/JunitTestRunner.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/JunitTestRunner.java index 0a3b2a911ea27..747a2106d5683 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/JunitTestRunner.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/JunitTestRunner.java @@ -327,11 +327,10 @@ public void reportingEntryPublished(TestIdentifier testIdentifier, ReportEntry e } QuarkusConsole.INSTANCE.setOutputFilter(null); - List historicFailures = testState.getHistoricFailures(resultsByClass); for (TestRunListener listener : listeners) { listener.runComplete(new TestRunResults(runId, classScanResult, classScanResult == null, start, - System.currentTimeMillis(), toResultsMap(historicFailures, resultsByClass))); + System.currentTimeMillis(), toResultsMap(testState.getCurrentResults()))); } } } catch (Exception e) { @@ -364,15 +363,10 @@ public synchronized void resume() { notifyAll(); } - private Map toResultsMap(List historicFailures, + private Map toResultsMap( Map> resultsByClass) { Map resultMap = new HashMap<>(); - Map> historicMap = new HashMap<>(); - for (TestResult i : historicFailures) { - historicMap.computeIfAbsent(i.getTestClass(), s -> new ArrayList<>()).add(i); - } Set classes = new HashSet<>(resultsByClass.keySet()); - classes.addAll(historicMap.keySet()); for (String clazz : classes) { List passing = new ArrayList<>(); List failing = new ArrayList<>(); @@ -386,15 +380,6 @@ private Map toResultsMap(List historicFailu passing.add(i); } } - for (TestResult i : Optional.ofNullable(historicMap.get(clazz)).orElse(Collections.emptyList())) { - if (i.getTestExecutionResult().getStatus() == TestExecutionResult.Status.FAILED) { - failing.add(i); - } else if (i.getTestExecutionResult().getStatus() == TestExecutionResult.Status.ABORTED) { - skipped.add(i); - } else { - passing.add(i); - } - } resultMap.put(clazz, new TestClassResult(clazz, passing, failing, skipped)); } return resultMap; diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java index acabe30aa54ce..b73a61cf7e9df 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java @@ -48,8 +48,7 @@ public void handleInput(int[] keys) { for (int k : keys) { if (k == 'r') { testController.runAllTests(); - } - if (k == 'f') { + } else if (k == 'f') { testController.runFailedTests(); } else if (k == 'v') { testController.printFullResults(); @@ -153,18 +152,19 @@ public void testComplete(TestResult result) { @Override public void runComplete(TestRunResults results) { + String resultString = String.format( + "%d/%d tests are failing (%d/%d from the last run). %d tests are skipped. Run %d took %dms.", + results.getFailedCount(), results.getTotalCount(), results.getCurrentFailedCount(), + results.getCurrentTotalCount(), results.getSkippedCount(), + results.getId(), results.getTotalTime()); firstRun = false; if (results.getCurrentFailing().isEmpty()) { - lastStatus = "\u001B[32mTests all passed, " + methodCount.get() + " tests were run, " + skipped.get() - + " were skipped. Tests took " + (results.getTotalTime()) - + "ms." + "\u001b[0m"; + lastStatus = "\u001B[32m" + resultString + "\u001b[0m"; } else { - int failedTestsNum = results.getCurrentFailing().values().stream().mapToInt((s) -> s.getFailing().size()) - .sum(); //TODO: this should not use the logger, it should print a nicer status log.error( - "==================== \u001B[91m" + failedTestsNum + " TESTS FAILED\u001b[0m ===================="); - boolean hasFailingTests = failedTestsNum > 0; + "==================== \u001B[91m" + results.getCurrentFailedCount() + + " TESTS FAILED\u001b[0m ===================="); for (Map.Entry classEntry : results.getCurrentFailing().entrySet()) { for (TestResult test : classEntry.getValue().getFailing()) { log.error( @@ -174,12 +174,7 @@ public void runComplete(TestRunResults results) { } log.error( "==================== \u001B[91mEND TEST REPORT\u001b[0m ===================="); - String output = String.format("Test run failed, %d tests were run, ", methodCount.get()) - + String.format("%s%d failed%s, ", - hasFailingTests ? "\u001B[1m" : "", failedTestsNum, - hasFailingTests ? "\u001B[2m" : "") - + String.format("%d were skipped. Tests took %dms", skipped.get(), results.getTotalTime()); - lastStatus = "\u001B[91m" + output + "\u001b[0m"; + lastStatus = "\u001B[91m" + resultString + "\u001b[0m"; } //this will re-print when using the basic console promptHandler.setPrompt(RUNNING_PROMPT); diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestRunResults.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestRunResults.java index e6e11fb65e823..e4a96544f492f 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestRunResults.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestRunResults.java @@ -36,9 +36,12 @@ public class TestRunResults { private final List failing = new ArrayList<>(); private final List passing = new ArrayList<>(); private final List skipped = new ArrayList<>(); - private final long testsPassed; - private final long testsFailed; - private final long testsSkipped; + private final long passedCount; + private final long failedCount; + private final long skippedCount; + private final long currentPassedCount; + private final long currentFailedCount; + private final long currentSkippedCount; public TestRunResults(long id, ClassScanResult trigger, boolean full, long started, long completed, Map results) { @@ -51,10 +54,16 @@ public TestRunResults(long id, ClassScanResult trigger, boolean full, long start long passedCount = 0; long failedCount = 0; long skippedCount = 0; + long currentPassedCount = 0; + long currentFailedCount = 0; + long currentSkippedCount = 0; for (Map.Entry i : results.entrySet()) { passedCount += i.getValue().getPassing().stream().filter(TestResult::isTest).count(); failedCount += i.getValue().getFailing().stream().filter(TestResult::isTest).count(); skippedCount += i.getValue().getSkipped().stream().filter(TestResult::isTest).count(); + currentPassedCount += i.getValue().getPassing().stream().filter(s -> s.isTest() && s.getRunId() == id).count(); + currentFailedCount += i.getValue().getFailing().stream().filter(s -> s.isTest() && s.getRunId() == id).count(); + currentSkippedCount += i.getValue().getSkipped().stream().filter(s -> s.isTest() && s.getRunId() == id).count(); boolean current = i.getValue().getLatestRunId() == id; if (current) { if (!i.getValue().getFailing().isEmpty()) { @@ -81,9 +90,12 @@ public TestRunResults(long id, ClassScanResult trigger, boolean full, long start Collections.sort(passing); Collections.sort(failing); Collections.sort(skipped); - this.testsFailed = failedCount; - this.testsPassed = passedCount; - this.testsSkipped = skippedCount; + this.failedCount = failedCount; + this.passedCount = passedCount; + this.skippedCount = skippedCount; + this.currentFailedCount = currentFailedCount; + this.currentPassedCount = currentPassedCount; + this.currentSkippedCount = currentSkippedCount; } public long getId() { @@ -142,15 +154,35 @@ public List getSkipped() { return skipped; } - public long getTestsPassed() { - return testsPassed; + public long getPassedCount() { + return passedCount; } - public long getTestsFailed() { - return testsFailed; + public long getFailedCount() { + return failedCount; } - public long getTestsSkipped() { - return testsSkipped; + public long getSkippedCount() { + return skippedCount; + } + + public long getCurrentPassedCount() { + return currentPassedCount; + } + + public long getCurrentFailedCount() { + return currentFailedCount; + } + + public long getCurrentSkippedCount() { + return currentSkippedCount; + } + + public long getTotalCount() { + return getPassedCount() + getFailedCount() + getSkippedCount(); + } + + public long getCurrentTotalCount() { + return getCurrentPassedCount() + getCurrentFailedCount() + getCurrentSkippedCount(); } } diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/console/ContinuousTestingWebSocketListener.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/console/ContinuousTestingWebSocketListener.java index b148cca1b7a74..86a5b7d8f05af 100644 --- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/console/ContinuousTestingWebSocketListener.java +++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/console/ContinuousTestingWebSocketListener.java @@ -48,11 +48,11 @@ public void testComplete(TestResult result) { public void runComplete(TestRunResults testRunResults) { ContinuousTestingWebsocketListener.setLastState( new ContinuousTestingWebsocketListener.State(true, false, - testRunResults.getTestsPassed() + - testRunResults.getTestsFailed() + - testRunResults.getTestsSkipped(), - testRunResults.getTestsPassed(), - testRunResults.getTestsFailed(), testRunResults.getTestsSkipped(), + testRunResults.getPassedCount() + + testRunResults.getFailedCount() + + testRunResults.getSkippedCount(), + testRunResults.getPassedCount(), + testRunResults.getFailedCount(), testRunResults.getSkippedCount(), ContinuousTestingWebsocketListener.getLastState().isBrokenOnly, ContinuousTestingWebsocketListener.getLastState().isTestOutput, ContinuousTestingWebsocketListener.getLastState().isInstrumentationBasedReload)); diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/tests/TestsProcessor.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/tests/TestsProcessor.java index 43247044cac5e..77516e57501e3 100644 --- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/tests/TestsProcessor.java +++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/tests/TestsProcessor.java @@ -82,10 +82,10 @@ public void handle(RoutingContext event) { testStatus.setRunning(status.getRunning()); if (status.getLastRun() > 0) { TestRunResults result = ts.get().getResults(); - testStatus.setTestsFailed(result.getTestsFailed()); - testStatus.setTestsPassed(result.getTestsPassed()); - testStatus.setTestsSkipped(result.getTestsSkipped()); - testStatus.setTestsRun(result.getTestsFailed() + result.getTestsPassed()); + testStatus.setTestsFailed(result.getCurrentFailedCount()); + testStatus.setTestsPassed(result.getCurrentPassedCount()); + testStatus.setTestsSkipped(result.getCurrentSkippedCount()); + testStatus.setTestsRun(result.getFailedCount() + result.getPassedCount()); } event.response().end(JsonObject.mapFrom(testStatus).encode()); } From cf44a680e4de6f2335c2dc6dd284267c7ef5cadc Mon Sep 17 00:00:00 2001 From: Foivos Zakkak Date: Thu, 13 May 2021 13:30:58 +0300 Subject: [PATCH 0065/2077] Workaround jpa-oracle failure when using Mandrel Works around issue https://github.com/graalvm/mandrel/issues/252 --- .../io/quarkus/jdbc/oracle/deployment/OracleReflections.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extensions/jdbc/jdbc-oracle/deployment/src/main/java/io/quarkus/jdbc/oracle/deployment/OracleReflections.java b/extensions/jdbc/jdbc-oracle/deployment/src/main/java/io/quarkus/jdbc/oracle/deployment/OracleReflections.java index 988f6059e19db..53854430001ff 100644 --- a/extensions/jdbc/jdbc-oracle/deployment/src/main/java/io/quarkus/jdbc/oracle/deployment/OracleReflections.java +++ b/extensions/jdbc/jdbc-oracle/deployment/src/main/java/io/quarkus/jdbc/oracle/deployment/OracleReflections.java @@ -39,5 +39,7 @@ void runtimeInitializeDriver(BuildProducer run "oracle.jdbc.driver.BlockSource$ThreadedCachingBlockSource$BlockReleaser")); runtimeInitialized.produce(new RuntimeInitializedClassBuildItem("oracle.net.nt.TimeoutInterruptHandler")); runtimeInitialized.produce(new RuntimeInitializedClassBuildItem("oracle.net.nt.Clock")); + runtimeInitialized.produce(new RuntimeInitializedClassBuildItem("oracle.jdbc.driver.NoSupportHAManager")); + runtimeInitialized.produce(new RuntimeInitializedClassBuildItem("oracle.jdbc.driver.LogicalConnection")); } } From f2cb51573d440b7f7358b466e1a5aeef03f36bc7 Mon Sep 17 00:00:00 2001 From: Phillip Kruger Date: Thu, 13 May 2021 13:11:27 +0200 Subject: [PATCH 0066/2077] DevUI: Ignore keybindings if input Signed-off-by:Phillip Kruger --- .../main/resources/dev-static/js/logstream.js | 40 +++++++++++-------- .../src/main/resources/dev-static/js/tests.js | 40 ++++++++++--------- 2 files changed, 45 insertions(+), 35 deletions(-) diff --git a/extensions/vertx-http/deployment/src/main/resources/dev-static/js/logstream.js b/extensions/vertx-http/deployment/src/main/resources/dev-static/js/logstream.js index 380e92b87cdfa..91b33dcf4ee0e 100644 --- a/extensions/vertx-http/deployment/src/main/resources/dev-static/js/logstream.js +++ b/extensions/vertx-http/deployment/src/main/resources/dev-static/js/logstream.js @@ -163,7 +163,9 @@ function addControlCListener(){ }); $(document).keydown(function (e) { - if (ctrlDown && (e.keyCode === cKey))stopLog(); + if (e.target.tagName === "BODY") { + if (ctrlDown && (e.keyCode === cKey))stopLog(); + } }); } @@ -181,32 +183,38 @@ function addScrollListener(){ } function addLineSpaceListener(){ - $(document).keydown(function (event) { - if (event.shiftKey && event.keyCode === 38) { - lineSpaceIncreaseEvent(); - }else if (event.shiftKey && event.keyCode === 40) { - lineSpaceDecreaseEvent(); + $(document).keydown(function (e) { + if (e.target.tagName === "BODY") { + if (e.shiftKey && e.keyCode === 38) { + lineSpaceIncreaseEvent(); + }else if (e.shiftKey && e.keyCode === 40) { + lineSpaceDecreaseEvent(); + } } }); } function addTabSizeListener(){ - $(document).keydown(function (event) { - if (event.shiftKey && event.keyCode === 39) { - tabSpaceIncreaseEvent(); - }else if (event.shiftKey && event.keyCode === 37) { - tabSpaceDecreaseEvent(); + $(document).keydown(function (e) { + if (e.target.tagName === "BODY") { + if (e.shiftKey && e.keyCode === 39) { + tabSpaceIncreaseEvent(); + }else if (e.shiftKey && e.keyCode === 37) { + tabSpaceDecreaseEvent(); + } } }); } function addEnterListener(){ $(document).keydown(function (e) { - if (e.keyCode === 13 && !$('#logstreamFilterModal').hasClass('show')){ - writeResponse("
"); - var element = document.getElementById("logstreamLogTerminal"); - element.scrollIntoView({block: "end"}); - } + if (e.target.tagName === "BODY") { + if (e.keyCode === 13 && !$('#logstreamFilterModal').hasClass('show')){ + writeResponse("
"); + var element = document.getElementById("logstreamLogTerminal"); + element.scrollIntoView({block: "end"}); + } + } }); } diff --git a/extensions/vertx-http/deployment/src/main/resources/dev-static/js/tests.js b/extensions/vertx-http/deployment/src/main/resources/dev-static/js/tests.js index 8aab5ed24677e..f9f2b948cacb9 100644 --- a/extensions/vertx-http/deployment/src/main/resources/dev-static/js/tests.js +++ b/extensions/vertx-http/deployment/src/main/resources/dev-static/js/tests.js @@ -115,26 +115,28 @@ function addTestsKeyListeners(){ var p = 80; // Pause tests $(document).keydown(function (e) { - if (e.keyCode === r){ - if(testsIsRunning){ - rerunAllTests(); - }else{ - startTests(); + if (e.target.tagName === "BODY") { + if (e.keyCode === r){ + if(testsIsRunning){ + rerunAllTests(); + }else{ + startTests(); + } + } else if (e.keyCode === f){ + rerunFailedTests(); + } else if (e.keyCode === b){ + toggleBrokenOnly(); + } else if (e.keyCode === v){ + printFailures(); + } else if (e.keyCode === o){ + toggleTestOutput(); + } else if (e.keyCode === i){ + toggleInstrumentationReload(); + } else if (e.keyCode === h){ + displayTestsHelp(); + } else if (e.keyCode === p){ + pauseTests(); } - } else if (e.keyCode === f){ - rerunFailedTests(); - } else if (e.keyCode === b){ - toggleBrokenOnly(); - } else if (e.keyCode === v){ - printFailures(); - } else if (e.keyCode === o){ - toggleTestOutput(); - } else if (e.keyCode === i){ - toggleInstrumentationReload(); - } else if (e.keyCode === h){ - displayTestsHelp(); - } else if (e.keyCode === p){ - pauseTests(); } }); } From 7df5cab84a6c8981ee4e335939c7f9856da76e0b Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Mon, 19 Apr 2021 17:56:19 +0100 Subject: [PATCH 0067/2077] Support for path-specific authentication mechanisms --- docs/src/main/asciidoc/security.adoc | 19 ++++++++ .../vertx/http/security/PathHandler.java | 2 +- .../http/runtime/PolicyMappingConfig.java | 7 +++ .../security/FormAuthenticationMechanism.java | 3 +- .../runtime/security/HttpAuthenticator.java | 43 +++++++++++++------ .../security/HttpCredentialTransport.java | 14 +++++- .../PathMatchingHttpSecurityPolicy.java | 23 ++++++++-- .../io/quarkus/it/keycloak/VertxResource.java | 27 ++++++++++++ .../src/main/resources/application.properties | 8 ++++ .../BearerTokenAuthorizationTest.java | 42 +++++++++++++++--- 10 files changed, 164 insertions(+), 24 deletions(-) diff --git a/docs/src/main/asciidoc/security.adoc b/docs/src/main/asciidoc/security.adoc index b994bdaafbabe..4d17cc5d1c282 100644 --- a/docs/src/main/asciidoc/security.adoc +++ b/docs/src/main/asciidoc/security.adoc @@ -207,6 +207,25 @@ You can also use link:security-testing#configuring-user-information[User Propert One can combine multiple authentication mechanisms if they get the authentication credentials from the different sources. For example, combining built-in `Basic` and `quarkus-oidc` `Bearer` authentication mechanisms is allowed, but combining `quarkus-oidc` `Bearer` and `smallrye-jwt` authentication mechanisms is not allowed because both will attempt to verify the token extracted from the HTTP `Authorization Bearer` scheme. +=== Path Specific Authentication Mechanism + +You can enforce that only a single authentication mechanism is selected for a given request path, for example: +[source,properties] +---- +quarkus.http.auth.permission.basic-or-bearer.paths=/service +quarkus.http.auth.permission.basic-or-bearer.policy=authenticated + +quarkus.http.auth.permission.basic.paths=/basic-only +quarkus.http.auth.permission.basic.policy=authenticated +quarkus.http.auth.permission.basic.auth-mechanism=basic + +quarkus.http.auth.permission.bearer.paths=/bearer-only +quarkus.http.auth.permission.bearer.policy=authenticated +quarkus.http.auth.permission.bearer.auth-mechanism=bearer +---- + +The value of the `auth-mechanism` property must match the authentication scheme supported by HttpAuthenticationMechanism such as `basic` or `bearer` or `form`, etc. + == Proactive Authentication By default, Quarkus does what we call proactive authentication. This means that if an incoming request has a diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/security/PathHandler.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/security/PathHandler.java index fe66f3b4ac9c2..f6e11b69bc47b 100644 --- a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/security/PathHandler.java +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/security/PathHandler.java @@ -21,7 +21,7 @@ public void handle(RoutingContext event) { ret.append(user.getSecurityIdentity().getPrincipal().getName()); } ret.append(":"); - ret.append(event.normalisedPath()); + ret.append(event.normalizedPath()); event.response().end(ret.toString()); } }); diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/PolicyMappingConfig.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/PolicyMappingConfig.java index 87705c6b0754c..007b4f4ad79d7 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/PolicyMappingConfig.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/PolicyMappingConfig.java @@ -53,4 +53,11 @@ public class PolicyMappingConfig { */ @ConfigItem public Optional> paths; + + /** + * Path specific authentication mechanism which must be used to authenticate a user. + * It needs to match {@link HttpCredentialTransport} authentication scheme such as 'basic', 'bearer', 'form', etc. + */ + @ConfigItem + public Optional authMechanism; } diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/FormAuthenticationMechanism.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/FormAuthenticationMechanism.java index a50815d6cd219..e69482a8f6693 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/FormAuthenticationMechanism.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/FormAuthenticationMechanism.java @@ -24,6 +24,7 @@ import io.vertx.ext.web.RoutingContext; public class FormAuthenticationMechanism implements HttpAuthenticationMechanism { + private static final String FORM = "form"; private static final Logger log = Logger.getLogger(FormAuthenticationMechanism.class); @@ -194,6 +195,6 @@ public Set> getCredentialTypes() { @Override public HttpCredentialTransport getCredentialTransport() { - return new HttpCredentialTransport(HttpCredentialTransport.Type.POST, postLocation); + return new HttpCredentialTransport(HttpCredentialTransport.Type.POST, postLocation, FORM); } } diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpAuthenticator.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpAuthenticator.java index 94f266f4597dd..8d8ddead5a142 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpAuthenticator.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpAuthenticator.java @@ -32,6 +32,8 @@ public class HttpAuthenticator { final HttpAuthenticationMechanism[] mechanisms; @Inject IdentityProviderManager identityProviderManager; + @Inject + Instance pathMatchingPolicy; public HttpAuthenticator() { mechanisms = null; @@ -98,9 +100,15 @@ IdentityProviderManager getIdentityProviderManager() { */ public Uni attemptAuthentication(RoutingContext routingContext) { - HttpAuthenticationMechanism matchingMech = findMechanismWithAuthorizationScheme(routingContext); + String pathSpecificMechanism = pathMatchingPolicy.isResolvable() + ? pathMatchingPolicy.get().getAuthMechanismName(routingContext) + : null; + HttpAuthenticationMechanism matchingMech = findBestCandidateMechanism(routingContext, pathSpecificMechanism); if (matchingMech != null) { + routingContext.put(HttpAuthenticationMechanism.class.getName(), matchingMech); return matchingMech.authenticate(routingContext, identityProviderManager); + } else if (pathSpecificMechanism != null) { + return Uni.createFrom().optional(Optional.empty()); } Uni result = mechanisms[0].authenticate(routingContext, identityProviderManager); @@ -126,7 +134,7 @@ public Uni apply(SecurityIdentity data) { public Uni sendChallenge(RoutingContext routingContext) { Uni result = null; - HttpAuthenticationMechanism matchingMech = findMechanismWithAuthorizationScheme(routingContext); + HttpAuthenticationMechanism matchingMech = routingContext.get(HttpAuthenticationMechanism.class.getName()); if (matchingMech != null) { result = matchingMech.sendChallenge(routingContext); } @@ -158,7 +166,7 @@ public Uni apply(Boolean authDone) { } public Uni getChallenge(RoutingContext routingContext) { - HttpAuthenticationMechanism matchingMech = findMechanismWithAuthorizationScheme(routingContext); + HttpAuthenticationMechanism matchingMech = routingContext.get(HttpAuthenticationMechanism.class.getName()); if (matchingMech != null) { return matchingMech.getChallenge(routingContext); } @@ -179,16 +187,25 @@ public Uni apply(ChallengeData data) { return result; } - private HttpAuthenticationMechanism findMechanismWithAuthorizationScheme(RoutingContext routingContext) { - String authScheme = getAuthorizationScheme(routingContext); - if (authScheme == null) { - return null; - } - for (int i = 0; i < mechanisms.length; ++i) { - HttpCredentialTransport credType = mechanisms[i].getCredentialTransport(); - if (credType != null && credType.getTransportType() == Type.AUTHORIZATION - && credType.getTypeTarget().toLowerCase().startsWith(authScheme.toLowerCase())) { - return mechanisms[i]; + private HttpAuthenticationMechanism findBestCandidateMechanism(RoutingContext routingContext, + String pathSpecificMechanism) { + if (pathSpecificMechanism != null) { + for (int i = 0; i < mechanisms.length; ++i) { + HttpCredentialTransport credType = mechanisms[i].getCredentialTransport(); + if (credType != null && credType.getAuthenticationScheme().equalsIgnoreCase(pathSpecificMechanism)) { + return mechanisms[i]; + } + } + } else { + String authScheme = getAuthorizationScheme(routingContext); + if (authScheme != null) { + for (int i = 0; i < mechanisms.length; ++i) { + HttpCredentialTransport credType = mechanisms[i].getCredentialTransport(); + if (credType != null && credType.getTransportType() == Type.AUTHORIZATION + && credType.getTypeTarget().toLowerCase().startsWith(authScheme.toLowerCase())) { + return mechanisms[i]; + } + } } } return null; diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpCredentialTransport.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpCredentialTransport.java index 4c978386d03d7..935f19193e9ef 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpCredentialTransport.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpCredentialTransport.java @@ -17,10 +17,16 @@ public class HttpCredentialTransport { private final Type transportType; private final String typeTarget; + private final String authenticationScheme; public HttpCredentialTransport(Type transportType, String typeTarget) { + this(transportType, typeTarget, typeTarget); + } + + public HttpCredentialTransport(Type transportType, String typeTarget, String authenticationScheme) { this.transportType = Objects.requireNonNull(transportType); this.typeTarget = Objects.requireNonNull(typeTarget).toLowerCase(); + this.authenticationScheme = Objects.requireNonNull(authenticationScheme); } public enum Type { @@ -57,13 +63,14 @@ public boolean equals(Object o) { if (transportType != that.transportType) return false; - return typeTarget.equals(that.typeTarget); + return typeTarget.equals(that.typeTarget) && this.authenticationScheme.equals(that.authenticationScheme); } @Override public int hashCode() { int result = transportType.hashCode(); result = 31 * result + typeTarget.hashCode(); + result = 31 * result + authenticationScheme.hashCode(); return result; } @@ -72,6 +79,7 @@ public String toString() { return "HttpCredentialTransport{" + "transportType=" + transportType + ", typeTarget='" + typeTarget + '\'' + + ", authenticationScheme='" + authenticationScheme + '\'' + '}'; } @@ -82,4 +90,8 @@ public Type getTransportType() { public String getTypeTarget() { return typeTarget; } + + public String getAuthenticationScheme() { + return authenticationScheme; + } } diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/PathMatchingHttpSecurityPolicy.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/PathMatchingHttpSecurityPolicy.java index b7464147b50cb..7ea671f190569 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/PathMatchingHttpSecurityPolicy.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/PathMatchingHttpSecurityPolicy.java @@ -29,6 +29,19 @@ public class PathMatchingHttpSecurityPolicy implements HttpSecurityPolicy { private final PathMatcher> pathMatcher = new PathMatcher<>(); + public String getAuthMechanismName(RoutingContext routingContext) { + PathMatcher.PathMatch> toCheck = pathMatcher.match(routingContext.request().path()); + if (toCheck.getValue() == null || toCheck.getValue().isEmpty()) { + return null; + } + for (HttpMatcher i : toCheck.getValue()) { + if (i.authMechanism != null) { + return i.authMechanism; + } + } + return null; + } + @Override public Uni checkPermission(RoutingContext routingContext, Uni identity, AuthorizationRequestContext requestContext) { @@ -87,11 +100,13 @@ void init(HttpBuildTimeConfig config, Map> for (String path : entry.getValue().paths.orElse(Collections.emptyList())) { path = path.trim(); if (tempMap.containsKey(path)) { - HttpMatcher m = new HttpMatcher(new HashSet<>(entry.getValue().methods.orElse(Collections.emptyList())), + HttpMatcher m = new HttpMatcher(entry.getValue().authMechanism.orElse(null), + new HashSet<>(entry.getValue().methods.orElse(Collections.emptyList())), checker); tempMap.get(path).add(m); } else { - HttpMatcher m = new HttpMatcher(new HashSet<>(entry.getValue().methods.orElse(Collections.emptyList())), + HttpMatcher m = new HttpMatcher(entry.getValue().authMechanism.orElse(null), + new HashSet<>(entry.getValue().methods.orElse(Collections.emptyList())), checker); List perms = new ArrayList<>(); tempMap.put(path, perms); @@ -137,12 +152,14 @@ public List findPermissionCheckers(HttpServerRequest request static class HttpMatcher { + final String authMechanism; final Set methods; final HttpSecurityPolicy checker; - HttpMatcher(Set methods, HttpSecurityPolicy checker) { + HttpMatcher(String authMechanism, Set methods, HttpSecurityPolicy checker) { this.methods = methods; this.checker = checker; + this.authMechanism = authMechanism; } } } diff --git a/integration-tests/oidc/src/main/java/io/quarkus/it/keycloak/VertxResource.java b/integration-tests/oidc/src/main/java/io/quarkus/it/keycloak/VertxResource.java index 1888ec72eabdc..360641f94595e 100644 --- a/integration-tests/oidc/src/main/java/io/quarkus/it/keycloak/VertxResource.java +++ b/integration-tests/oidc/src/main/java/io/quarkus/it/keycloak/VertxResource.java @@ -3,6 +3,7 @@ import javax.enterprise.context.ApplicationScoped; import javax.enterprise.event.Observes; +import io.quarkus.vertx.http.runtime.security.QuarkusHttpUser; import io.vertx.core.Handler; import io.vertx.core.buffer.Buffer; import io.vertx.ext.web.Router; @@ -23,6 +24,32 @@ public void handle(Buffer data) { }); } }); + router.route("/basic-only").handler(new Handler() { + @Override + public void handle(RoutingContext event) { + QuarkusHttpUser user = (QuarkusHttpUser) event.user(); + StringBuilder ret = new StringBuilder(); + if (user != null) { + ret.append(user.getSecurityIdentity().getPrincipal().getName()); + } + ret.append(":"); + ret.append(event.normalizedPath()); + event.response().end(ret.toString()); + } + }); + router.route("/bearer-only").handler(new Handler() { + @Override + public void handle(RoutingContext event) { + QuarkusHttpUser user = (QuarkusHttpUser) event.user(); + StringBuilder ret = new StringBuilder(); + if (user != null) { + ret.append(user.getSecurityIdentity().getPrincipal().getName()); + } + ret.append(":"); + ret.append(event.normalizedPath()); + event.response().end(ret.toString()); + } + }); } } diff --git a/integration-tests/oidc/src/main/resources/application.properties b/integration-tests/oidc/src/main/resources/application.properties index 7229843c206cb..c0d1e79accd26 100644 --- a/integration-tests/oidc/src/main/resources/application.properties +++ b/integration-tests/oidc/src/main/resources/application.properties @@ -11,3 +11,11 @@ quarkus.security.users.embedded.enabled=true quarkus.security.users.embedded.plain-text=true quarkus.security.users.embedded.users.alice=password quarkus.security.users.embedded.roles.alice=user + +quarkus.http.auth.permission.basic.paths=/basic-only +quarkus.http.auth.permission.basic.policy=authenticated +quarkus.http.auth.permission.basic.auth-mechanism=basic + +quarkus.http.auth.permission.bearer.paths=/bearer-only +quarkus.http.auth.permission.bearer.policy=authenticated +quarkus.http.auth.permission.bearer.auth-mechanism=bearer \ No newline at end of file diff --git a/integration-tests/oidc/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java b/integration-tests/oidc/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java index 5cc88a26da049..df48ce27f3d83 100644 --- a/integration-tests/oidc/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java +++ b/integration-tests/oidc/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java @@ -5,9 +5,7 @@ import static org.awaitility.Awaitility.await; import static org.hamcrest.Matchers.equalTo; -import java.nio.charset.StandardCharsets; import java.util.Arrays; -import java.util.Base64; import java.util.concurrent.TimeUnit; import org.hamcrest.Matchers; @@ -63,9 +61,8 @@ public void testSecureAccessSuccessCustomPrincipal() { @Test public void testBasicAuth() { - byte[] basicAuthBytes = "alice:password".getBytes(StandardCharsets.UTF_8); - RestAssured.given() - .header("Authorization", "Basic " + Base64.getEncoder().encodeToString(basicAuthBytes)) + RestAssured.given().auth() + .preemptive().basic("alice", "password") .when().get("/api/users/me") .then() .statusCode(200) @@ -159,6 +156,41 @@ public void testOidcAndVertxHandler() { .body(equalTo("Hello World")); } + @Test + public void testBearerAuthFailureWhereBasicIsRequired() { + RestAssured.given().auth().oauth2(getAccessToken("alice")) + .when().get("/basic-only") + .then() + .statusCode(401); + } + + @Test + public void testBasicAuthWhereBasicIsRequired() { + RestAssured.given().auth() + .preemptive().basic("alice", "password") + .when().get("/basic-only") + .then() + .statusCode(200) + .body(equalTo("alice:/basic-only")); + } + + @Test + public void testBasicAuthFailureWhereBearerIsRequired() { + RestAssured.given().auth().preemptive().basic("alice", "password") + .when().get("/bearer-only") + .then() + .statusCode(401); + } + + @Test + public void testBearerAuthWhereBasicIsRequired() { + RestAssured.given().auth().oauth2(getAccessToken("alice")) + .when().get("/bearer-only") + .then() + .statusCode(200) + .body(equalTo("alice@gmail.com:/bearer-only")); + } + @Test public void testExpiredBearerToken() throws InterruptedException { String token = getAccessToken("alice"); From d92300a01126adf1ae098fd586b765ec40da67ff Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Wed, 12 May 2021 21:53:05 -0300 Subject: [PATCH 0068/2077] Honor GenerateResourceBuildItem while building UberJar --- .../quarkus/deployment/pkg/PackageConfig.java | 4 ++ .../pkg/steps/JarResultBuildStep.java | 19 ++++-- core/test-extension/deployment/pom.xml | 8 +++ .../deployment/UberJarConfigBuildStep.java | 38 +++++++++++ .../GeneratedResourceBuildItemTest.java | 65 +++++++++++++++++++ 5 files changed, 127 insertions(+), 7 deletions(-) create mode 100644 core/test-extension/deployment/src/test/java/io/quarkus/deployment/pkg/builditem/GeneratedResourceBuildItemTest.java diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/PackageConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/PackageConfig.java index e5918d4cd3df6..778fad0cbe869 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/pkg/PackageConfig.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/PackageConfig.java @@ -176,6 +176,10 @@ public boolean isLegacyJar() { type.equalsIgnoreCase(PackageConfig.LEGACY)); } + public boolean isUberJar() { + return type.equalsIgnoreCase(PackageConfig.UBER_JAR); + } + @ConfigGroup public static class FernflowerConfig { diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/JarResultBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/JarResultBuildStep.java index 92d924d1a5154..4ca4cb54ec5f3 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/JarResultBuildStep.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/JarResultBuildStep.java @@ -355,18 +355,25 @@ private void buildUberJar0(CurateOutcomeBuildItem curateOutcomeBuildItem, } for (Path resolvedDep : depArtifact.getPaths()) { - Set transformedFromThisArchive = transformedClasses.getTransformedFilesByJar().get(resolvedDep); + Set existingEntries = new HashSet<>(); + Set transformedFilesByJar = transformedClasses.getTransformedFilesByJar().get(resolvedDep); + if (transformedFilesByJar != null) { + existingEntries.addAll(transformedFilesByJar); + } + generatedResources.stream() + .map(GeneratedResourceBuildItem::getName) + .forEach(existingEntries::add); if (!Files.isDirectory(resolvedDep)) { try (FileSystem artifactFs = ZipUtils.newFileSystem(resolvedDep)) { for (final Path root : artifactFs.getRootDirectories()) { walkFileDependencyForDependency(root, runnerZipFs, seen, duplicateCatcher, concatenatedEntries, - finalIgnoredEntries, appDep, transformedFromThisArchive, mergeResourcePaths); + finalIgnoredEntries, appDep, existingEntries, mergeResourcePaths); } } } else { walkFileDependencyForDependency(resolvedDep, runnerZipFs, seen, duplicateCatcher, - concatenatedEntries, finalIgnoredEntries, appDep, transformedFromThisArchive, + concatenatedEntries, finalIgnoredEntries, appDep, existingEntries, mergeResourcePaths); } } @@ -416,7 +423,7 @@ private static boolean includeAppDep(AppDependency appDep, Optional seen, Map> duplicateCatcher, Map> concatenatedEntries, - Set finalIgnoredEntries, AppDependency appDep, Set transformedFromThisArchive, + Set finalIgnoredEntries, AppDependency appDep, Set existingEntries, Set mergeResourcePaths) throws IOException { final Path metaInfDir = root.resolve("META-INF"); Files.walkFileTree(root, EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, @@ -446,9 +453,7 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) } return FileVisitResult.CONTINUE; } - boolean transformed = transformedFromThisArchive != null - && transformedFromThisArchive.contains(relativePath); - if (!transformed) { + if (!existingEntries.contains(relativePath)) { if (CONCATENATED_ENTRIES_PREDICATE.test(relativePath) || mergeResourcePaths.contains(relativePath)) { concatenatedEntries.computeIfAbsent(relativePath, (u) -> new ArrayList<>()) diff --git a/core/test-extension/deployment/pom.xml b/core/test-extension/deployment/pom.xml index eb4318b63fe34..686f3667dc567 100644 --- a/core/test-extension/deployment/pom.xml +++ b/core/test-extension/deployment/pom.xml @@ -12,6 +12,9 @@ quarkus-test-extension-deployment Quarkus - Core - Test Extension - Deployment + + 3.0.0 + io.quarkus @@ -30,6 +33,11 @@ quarkus-test-extension ${project.version} + + org.atteo + xml-combiner + ${xml-combiner.version} + diff --git a/core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/UberJarConfigBuildStep.java b/core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/UberJarConfigBuildStep.java index 5299b7832ebb8..6f0a1e1b9c263 100644 --- a/core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/UberJarConfigBuildStep.java +++ b/core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/UberJarConfigBuildStep.java @@ -1,6 +1,22 @@ package io.quarkus.extest.deployment; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Collections; +import java.util.List; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; + +import org.atteo.xmlcombiner.XmlCombiner; +import org.xml.sax.SAXException; + +import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.builditem.GeneratedResourceBuildItem; +import io.quarkus.deployment.pkg.PackageConfig; import io.quarkus.deployment.pkg.builditem.UberJarIgnoredResourceBuildItem; import io.quarkus.deployment.pkg.builditem.UberJarMergedResourceBuildItem; @@ -14,6 +30,28 @@ UberJarMergedResourceBuildItem uberJarMergedResourceBuildItem() { return new UberJarMergedResourceBuildItem("META-INF/cxf/bus-extensions.txt"); } + @BuildStep + void uberJarMergedResourceBuildItem(BuildProducer generatedResourcesProducer, + PackageConfig packageConfig) { + if (packageConfig.isUberJar()) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + XmlCombiner combiner = new XmlCombiner(); + List resources = Collections + .list(getClass().getClassLoader().getResources("META-INF/wsdl.plugin.xml")); + for (URL resource : resources) { + try (InputStream is = resource.openStream()) { + combiner.combine(is); + } + } + combiner.buildDocument(baos); + } catch (ParserConfigurationException | SAXException | TransformerException | IOException e) { + e.printStackTrace(); + } + generatedResourcesProducer.produce(new GeneratedResourceBuildItem("META-INF/wsdl.plugin.xml", baos.toByteArray())); + } + } + @BuildStep UberJarIgnoredResourceBuildItem uberJarIgnoredResourceBuildItem() { return new UberJarIgnoredResourceBuildItem("META-INF/cxf/cxf.fixml"); diff --git a/core/test-extension/deployment/src/test/java/io/quarkus/deployment/pkg/builditem/GeneratedResourceBuildItemTest.java b/core/test-extension/deployment/src/test/java/io/quarkus/deployment/pkg/builditem/GeneratedResourceBuildItemTest.java new file mode 100644 index 0000000000000..38ce6efbff182 --- /dev/null +++ b/core/test-extension/deployment/src/test/java/io/quarkus/deployment/pkg/builditem/GeneratedResourceBuildItemTest.java @@ -0,0 +1,65 @@ +package io.quarkus.deployment.pkg.builditem; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.bootstrap.model.AppArtifact; +import io.quarkus.runtime.annotations.QuarkusMain; +import io.quarkus.test.QuarkusProdModeTest; + +class GeneratedResourceBuildItemTest { + + @RegisterExtension + static final QuarkusProdModeTest runner = new QuarkusProdModeTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addAsManifestResource("application.properties", "microprofile-config.properties") + .addClass(UberJarMain.class)) + .setApplicationName("generated-resource") + .setApplicationVersion("0.1-SNAPSHOT") + .setRun(true) + .setExpectExit(true) + .overrideConfigKey("quarkus.package.type", "uber-jar") + .setForcedDependencies( + Arrays.asList( + new AppArtifact("org.apache.cxf", "cxf-rt-bindings-xml", "3.4.3"), + new AppArtifact("org.apache.cxf", "cxf-rt-bindings-soap", "3.4.3"))); + + @Test + public void testXMLResourceWasMerged() throws IOException { + assertThat(runner.getStartupConsoleOutput()).contains("RESOURCES: 1", + "org.apache.cxf.binding.xml.wsdl11.HttpAddressPlugin", + "org.apache.cxf.binding.xml.wsdl11.XmlBindingPlugin", + "org.apache.cxf.binding.xml.wsdl11.XmlIoPlugin", + "org.apache.cxf.binding.xml.wsdl11.XmlIoPlugin", + "org.apache.cxf.binding.soap.wsdl11.SoapAddressPlugin"); + assertThat(runner.getExitCode()).isZero(); + } + + @QuarkusMain + public static class UberJarMain { + + public static void main(String[] args) throws IOException { + List resources = Collections + .list(UberJarMain.class.getClassLoader().getResources("META-INF/wsdl.plugin.xml")); + System.out.println("RESOURCES: " + resources.size()); + try (InputStream is = resources.get(0).openStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { + reader.lines().forEach(System.out::println); + } + } + } +} From c4da1b5d2c6edd407b1738b6b039e508a32c2b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Mathieu?= Date: Fri, 26 Mar 2021 11:13:42 +0100 Subject: [PATCH 0069/2077] Create a MongoDB test extension --- bom/application/pom.xml | 20 +++-- docs/src/main/asciidoc/mongodb.adoc | 13 ++- integration-tests/mongodb-client/pom.xml | 4 +- .../src/main/resources/application.properties | 4 +- .../quarkus/it/mongodb/BookResourceTest.java | 2 +- ...ookResourceWithParameterInjectionTest.java | 3 +- .../mongodb-panache-kotlin/pom.xml | 4 +- .../src/main/resources/application.properties | 4 +- .../it/mongodb/panache/MongoTestResource.kt | 82 ------------------ .../panache/MongodbPanacheMockingTest.kt | 5 +- .../panache/MongodbPanacheResourceTest.kt | 5 +- .../NativeMongodbPanacheResourceIT.kt | 0 .../ReactiveMongodbPanacheResourceTest.kt | 10 +-- integration-tests/mongodb-panache/pom.xml | 4 +- .../src/main/resources/application.properties | 4 +- .../it/mongodb/panache/MongoTestResource.java | 86 ------------------- .../panache/MongodbPanacheMockingTest.java | 1 + .../panache/MongodbPanacheResourceTest.java | 1 + .../ReactiveMongodbPanacheMockingTest.java | 2 +- .../ReactiveMongodbPanacheResourceTest.java | 2 +- .../MongodbPanacheTransactionTest.java | 2 +- .../mongodb-rest-data-panache/pom.xml | 5 ++ .../src/main/resources/application.properties | 1 + .../panache/MongoDbRestDataPanacheTest.java | 3 + test-framework/mongodb/pom.xml | 33 +++++++ .../mongodb}/MongoReplicaSetTestResource.java | 14 ++- .../test}/mongodb/MongoTestResource.java | 4 +- test-framework/pom.xml | 1 + 28 files changed, 115 insertions(+), 204 deletions(-) delete mode 100644 integration-tests/mongodb-panache-kotlin/src/test/kotlin/io/quarkus/it/mongodb/panache/MongoTestResource.kt rename integration-tests/mongodb-panache-kotlin/src/test/kotlin/io/quarkus/it/mongodb/panache/{reactive => }/NativeMongodbPanacheResourceIT.kt (100%) delete mode 100644 integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongoTestResource.java create mode 100644 test-framework/mongodb/pom.xml rename {integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache => test-framework/mongodb/src/main/java/io/quarkus/test/mongodb}/MongoReplicaSetTestResource.java (92%) rename {integration-tests/mongodb-client/src/test/java/io/quarkus/it => test-framework/mongodb/src/main/java/io/quarkus/test}/mongodb/MongoTestResource.java (98%) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index b64c7d11d14cb..025ba9af30388 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -833,11 +833,6 @@ quarkus-panache-common-deployment ${project.version} - - io.quarkus - quarkus-mongodb-panache-common-deployment - ${project.version} - io.quarkus quarkus-panache-hibernate-common @@ -953,11 +948,21 @@ quarkus-mongodb-panache-kotlin ${project.version} + + io.quarkus + quarkus-mongodb-panache-kotlin-deployment + ${project.version} + io.quarkus quarkus-mongodb-panache-common ${project.version} + + io.quarkus + quarkus-mongodb-panache-common-deployment + ${project.version} + io.quarkus quarkus-hibernate-search-orm-elasticsearch @@ -1530,6 +1535,11 @@ quarkus-mongodb-client-deployment ${project.version} + + io.quarkus + quarkus-test-mongodb + ${project.version} + io.quarkus quarkus-grpc diff --git a/docs/src/main/asciidoc/mongodb.adoc b/docs/src/main/asciidoc/mongodb.adoc index 8c2cb3af8cbad..dc1431148376f 100644 --- a/docs/src/main/asciidoc/mongodb.adoc +++ b/docs/src/main/asciidoc/mongodb.adoc @@ -605,7 +605,7 @@ If you are using the `quarkus-micrometer` or `quarkus-smallrye-metrics` extensio This behavior must first be enabled by setting the `quarkus.mongodb.metrics.enabled` property to `true` in your `application.properties`. So when you access the `/q/metrics` endpoint of your application you will have information about the connection pool status. -When using link:microprofile-metrics[SmallRye Metrics], connection pool metrics will be available under the `vendor` scope. +When using link:smallrye-metrics[SmallRye Metrics], connection pool metrics will be available under the `vendor` scope. == Tracing @@ -614,6 +614,17 @@ This behavior must be enabled by setting the `quarkus.mongodb.tracing.enabled` p Read the link:opentracing[OpenTracing] guide, for how to configure OpenTracing and how to use the Jaeger tracer. +== Testing helpers + +To start a MongoDB database for your unit tests, Quarkus provides two `QuarkusTestResourceLifecycleManager` that relies on link:https://github.com/flapdoodle-oss/de.flapdoodle.embed.mongo[Flapdoodle embedded MongoDB]. + +- `io.quarkus.test.mongodb.MongoTestResource` will start a single instance on port 27017. +- `io.quarkus.test.mongodb.MongoReplicaSetTestResource` will start a replicaset with two instances, one on port 27017 and the other on port 27018. + +To use them, you need to add the `io.quarkus:quarkus-test-mongodb` dependency to your pom.xml. + +For more information about the usage of a `QuarkusTestResourceLifecycleManager` please read link:getting-started-testing#quarkus-test-resource[Quarkus test resource]. + == The legacy client We don't include the legacy MongoDB client by default. It contains the now retired MongoDB Java API (DB, DBCollection,... ) diff --git a/integration-tests/mongodb-client/pom.xml b/integration-tests/mongodb-client/pom.xml index 39f32dcedd314..82960b4f2ffdf 100644 --- a/integration-tests/mongodb-client/pom.xml +++ b/integration-tests/mongodb-client/pom.xml @@ -45,8 +45,8 @@ test - de.flapdoodle.embed - de.flapdoodle.embed.mongo + io.quarkus + quarkus-test-mongodb test diff --git a/integration-tests/mongodb-client/src/main/resources/application.properties b/integration-tests/mongodb-client/src/main/resources/application.properties index 47c195fe3393e..b530bed6af062 100644 --- a/integration-tests/mongodb-client/src/main/resources/application.properties +++ b/integration-tests/mongodb-client/src/main/resources/application.properties @@ -1,4 +1,4 @@ -quarkus.mongodb.connection-string=mongodb://localhost:27018 +quarkus.mongodb.connection-string=mongodb://localhost:27017 quarkus.mongodb.write-concern.journal=false -quarkus.mongodb.parameter-injection.connection-string=mongodb://localhost:27018 +quarkus.mongodb.parameter-injection.connection-string=mongodb://localhost:27017 quarkus.mongodb.parameter-injection.write-concern.journal=false \ No newline at end of file diff --git a/integration-tests/mongodb-client/src/test/java/io/quarkus/it/mongodb/BookResourceTest.java b/integration-tests/mongodb-client/src/test/java/io/quarkus/it/mongodb/BookResourceTest.java index a46fbd778b4b1..b5bbc1750853a 100644 --- a/integration-tests/mongodb-client/src/test/java/io/quarkus/it/mongodb/BookResourceTest.java +++ b/integration-tests/mongodb-client/src/test/java/io/quarkus/it/mongodb/BookResourceTest.java @@ -1,6 +1,5 @@ package io.quarkus.it.mongodb; -import static io.restassured.RestAssured.get; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.hasKey; import static org.hamcrest.Matchers.is; @@ -14,6 +13,7 @@ import io.quarkus.mongodb.health.MongoHealthCheck; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.mongodb.MongoTestResource; import io.restassured.RestAssured; @QuarkusTest diff --git a/integration-tests/mongodb-client/src/test/java/io/quarkus/it/mongodb/BookResourceWithParameterInjectionTest.java b/integration-tests/mongodb-client/src/test/java/io/quarkus/it/mongodb/BookResourceWithParameterInjectionTest.java index d9399564e0b7f..3dce47f6694c2 100644 --- a/integration-tests/mongodb-client/src/test/java/io/quarkus/it/mongodb/BookResourceWithParameterInjectionTest.java +++ b/integration-tests/mongodb-client/src/test/java/io/quarkus/it/mongodb/BookResourceWithParameterInjectionTest.java @@ -1,7 +1,5 @@ package io.quarkus.it.mongodb; -import static org.hamcrest.Matchers.*; - import javax.json.bind.Jsonb; import org.junit.jupiter.api.AfterAll; @@ -10,6 +8,7 @@ import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.mongodb.MongoTestResource; @QuarkusTest @QuarkusTestResource(MongoTestResource.class) diff --git a/integration-tests/mongodb-panache-kotlin/pom.xml b/integration-tests/mongodb-panache-kotlin/pom.xml index 930b7ec64eff9..28d16a4630bfb 100755 --- a/integration-tests/mongodb-panache-kotlin/pom.xml +++ b/integration-tests/mongodb-panache-kotlin/pom.xml @@ -76,8 +76,8 @@ test
- de.flapdoodle.embed - de.flapdoodle.embed.mongo + io.quarkus + quarkus-test-mongodb test diff --git a/integration-tests/mongodb-panache-kotlin/src/main/resources/application.properties b/integration-tests/mongodb-panache-kotlin/src/main/resources/application.properties index bde8c47826706..7722b2d9904e7 100644 --- a/integration-tests/mongodb-panache-kotlin/src/main/resources/application.properties +++ b/integration-tests/mongodb-panache-kotlin/src/main/resources/application.properties @@ -1,9 +1,9 @@ -quarkus.mongodb.connection-string=mongodb://localhost:27018 +quarkus.mongodb.connection-string=mongodb://localhost:27017 quarkus.mongodb.write-concern.journal=false quarkus.mongodb.database=books # fake a different MongoDB instance -quarkus.mongodb.cl2.connection-string=mongodb://localhost:27018 +quarkus.mongodb.cl2.connection-string=mongodb://localhost:27017 quarkus.mongodb.cl2.write-concern.journal=false #quarkus.log.category."io.quarkus.mongodb.panache.runtime".level=DEBUG diff --git a/integration-tests/mongodb-panache-kotlin/src/test/kotlin/io/quarkus/it/mongodb/panache/MongoTestResource.kt b/integration-tests/mongodb-panache-kotlin/src/test/kotlin/io/quarkus/it/mongodb/panache/MongoTestResource.kt deleted file mode 100644 index de90b8189d530..0000000000000 --- a/integration-tests/mongodb-panache-kotlin/src/test/kotlin/io/quarkus/it/mongodb/panache/MongoTestResource.kt +++ /dev/null @@ -1,82 +0,0 @@ -package io.quarkus.it.mongodb.panache - -import de.flapdoodle.embed.mongo.Command -import de.flapdoodle.embed.mongo.MongodExecutable -import de.flapdoodle.embed.mongo.MongodStarter -import de.flapdoodle.embed.mongo.config.IMongodConfig -import de.flapdoodle.embed.mongo.config.MongodConfigBuilder -import de.flapdoodle.embed.mongo.config.Net -import de.flapdoodle.embed.mongo.config.RuntimeConfigBuilder -import de.flapdoodle.embed.mongo.distribution.Version -import de.flapdoodle.embed.process.config.io.ProcessOutput -import de.flapdoodle.embed.process.io.Processors -import de.flapdoodle.embed.process.runtime.Network -import io.quarkus.test.common.QuarkusTestResourceLifecycleManager -import org.jboss.logging.Logger - -class MongoTestResource : QuarkusTestResourceLifecycleManager { - companion object { - private val LOGGER: Logger = Logger.getLogger(MongoTestResource::class.java) - } - - private var mongod: MongodExecutable? = null - - override fun start(): Map { - try { - //JDK bug workaround - //https://github.com/quarkusio/quarkus/issues/14424 - //force class init to prevent possible deadlock when done by mongo threads - Class.forName("sun.net.ext.ExtendedSocketOptions", true, ClassLoader.getSystemClassLoader()); - } catch (e: ClassNotFoundException) { - } - return try { - val version: Version.Main = Version.Main.V4_0 - val port = 27018 - LOGGER.infof("Starting Mongo %s on port %s", version, port) - val config: IMongodConfig = MongodConfigBuilder() - .version(version) - .net(Net(port, Network.localhostIsIPv6())) - .build() - mongod = getMongodExecutable(config).also { - try { - it.start() - } catch (e: Exception) { - //every so often mongo fails to start on CI runs - //see if this helps - Thread.sleep(1000) - it.start() - } - - } - mapOf() - } catch (e: Exception) { - throw RuntimeException(e) - } - } - - private fun getMongodExecutable(config: IMongodConfig): MongodExecutable { - return try { - doGetExecutable(config) - } catch (e: Exception) { - // sometimes the download process can timeout so just sleep and try again - try { - Thread.sleep(1000) - } catch (ignored: InterruptedException) { - } - doGetExecutable(config) - } - } - - private fun doGetExecutable(config: IMongodConfig): MongodExecutable { - val runtimeConfig = RuntimeConfigBuilder() - .defaults(Command.MongoD) - .processOutput(ProcessOutput(Processors.silent(), - Processors.silent(), Processors.silent())) - .build() - return MongodStarter.getInstance(runtimeConfig).prepare(config) - } - - override fun stop() { - mongod?.stop() - } -} diff --git a/integration-tests/mongodb-panache-kotlin/src/test/kotlin/io/quarkus/it/mongodb/panache/MongodbPanacheMockingTest.kt b/integration-tests/mongodb-panache-kotlin/src/test/kotlin/io/quarkus/it/mongodb/panache/MongodbPanacheMockingTest.kt index 2fe71cd4e42b8..09e35c6c7017d 100644 --- a/integration-tests/mongodb-panache-kotlin/src/test/kotlin/io/quarkus/it/mongodb/panache/MongodbPanacheMockingTest.kt +++ b/integration-tests/mongodb-panache-kotlin/src/test/kotlin/io/quarkus/it/mongodb/panache/MongodbPanacheMockingTest.kt @@ -8,15 +8,18 @@ import io.quarkus.mongodb.panache.kotlin.PanacheMongoRepositoryBase import io.quarkus.test.common.QuarkusTestResource import io.quarkus.test.junit.QuarkusTest import io.quarkus.test.junit.mockito.InjectMock +import io.quarkus.test.mongodb.MongoTestResource import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test +import org.junit.jupiter.api.condition.DisabledOnOs +import org.junit.jupiter.api.condition.OS import org.mockito.Mockito import java.util.Collections import javax.inject.Inject import javax.ws.rs.WebApplicationException @QuarkusTest -@QuarkusTestResource(MongoTestResource::class) +@DisabledOnOs(OS.WINDOWS) class MongodbPanacheMockingTest { @Inject lateinit var realPersonRepository: PersonRepository diff --git a/integration-tests/mongodb-panache-kotlin/src/test/kotlin/io/quarkus/it/mongodb/panache/MongodbPanacheResourceTest.kt b/integration-tests/mongodb-panache-kotlin/src/test/kotlin/io/quarkus/it/mongodb/panache/MongodbPanacheResourceTest.kt index c46756da682d8..a20e75f88f06f 100644 --- a/integration-tests/mongodb-panache-kotlin/src/test/kotlin/io/quarkus/it/mongodb/panache/MongodbPanacheResourceTest.kt +++ b/integration-tests/mongodb-panache-kotlin/src/test/kotlin/io/quarkus/it/mongodb/panache/MongodbPanacheResourceTest.kt @@ -6,9 +6,9 @@ import com.fasterxml.jackson.datatype.jdk8.Jdk8Module import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule import io.quarkus.it.mongodb.panache.book.BookDetail import io.quarkus.it.mongodb.panache.person.Person -import io.quarkus.it.mongodb.panache.person.PersonEntity import io.quarkus.test.common.QuarkusTestResource import io.quarkus.test.junit.QuarkusTest +import io.quarkus.test.mongodb.MongoTestResource import io.restassured.RestAssured import io.restassured.RestAssured.get import io.restassured.common.mapper.TypeRef @@ -18,6 +18,8 @@ import io.restassured.response.Response import org.hamcrest.Matchers.`is` import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test +import org.junit.jupiter.api.condition.DisabledOnOs +import org.junit.jupiter.api.condition.OS import java.util.Calendar import java.util.Collections import java.util.Date @@ -25,6 +27,7 @@ import java.util.GregorianCalendar @QuarkusTest @QuarkusTestResource(MongoTestResource::class) +@DisabledOnOs(OS.WINDOWS) open class MongodbPanacheResourceTest { @Test fun testBookEntity() { diff --git a/integration-tests/mongodb-panache-kotlin/src/test/kotlin/io/quarkus/it/mongodb/panache/reactive/NativeMongodbPanacheResourceIT.kt b/integration-tests/mongodb-panache-kotlin/src/test/kotlin/io/quarkus/it/mongodb/panache/NativeMongodbPanacheResourceIT.kt similarity index 100% rename from integration-tests/mongodb-panache-kotlin/src/test/kotlin/io/quarkus/it/mongodb/panache/reactive/NativeMongodbPanacheResourceIT.kt rename to integration-tests/mongodb-panache-kotlin/src/test/kotlin/io/quarkus/it/mongodb/panache/NativeMongodbPanacheResourceIT.kt diff --git a/integration-tests/mongodb-panache-kotlin/src/test/kotlin/io/quarkus/it/mongodb/panache/reactive/ReactiveMongodbPanacheResourceTest.kt b/integration-tests/mongodb-panache-kotlin/src/test/kotlin/io/quarkus/it/mongodb/panache/reactive/ReactiveMongodbPanacheResourceTest.kt index 283139f1e4865..d16f81005d8b1 100644 --- a/integration-tests/mongodb-panache-kotlin/src/test/kotlin/io/quarkus/it/mongodb/panache/reactive/ReactiveMongodbPanacheResourceTest.kt +++ b/integration-tests/mongodb-panache-kotlin/src/test/kotlin/io/quarkus/it/mongodb/panache/reactive/ReactiveMongodbPanacheResourceTest.kt @@ -5,11 +5,11 @@ import com.fasterxml.jackson.databind.SerializationFeature import com.fasterxml.jackson.datatype.jdk8.Jdk8Module import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule import io.quarkus.it.mongodb.panache.BookDTO -import io.quarkus.it.mongodb.panache.MongoTestResource import io.quarkus.it.mongodb.panache.book.BookDetail import io.quarkus.it.mongodb.panache.person.Person import io.quarkus.test.common.QuarkusTestResource import io.quarkus.test.junit.QuarkusTest +import io.quarkus.test.mongodb.MongoTestResource import io.restassured.RestAssured import io.restassured.RestAssured.get import io.restassured.common.mapper.TypeRef @@ -21,12 +21,11 @@ import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertNotNull import org.junit.jupiter.api.Test +import org.junit.jupiter.api.condition.DisabledOnOs +import org.junit.jupiter.api.condition.OS import java.io.IOException import java.time.Duration -import java.util.Calendar -import java.util.Collections -import java.util.Date -import java.util.GregorianCalendar +import java.util.* import javax.ws.rs.client.Client import javax.ws.rs.client.ClientBuilder import javax.ws.rs.client.WebTarget @@ -34,6 +33,7 @@ import javax.ws.rs.sse.SseEventSource @QuarkusTest @QuarkusTestResource(MongoTestResource::class) +@DisabledOnOs(OS.WINDOWS) internal open class ReactiveMongodbPanacheResourceTest { companion object { private val LIST_OF_BOOK_TYPE_REF: TypeRef> = object : TypeRef>() {} diff --git a/integration-tests/mongodb-panache/pom.xml b/integration-tests/mongodb-panache/pom.xml index e5a7dd8249951..ffe696335aa80 100755 --- a/integration-tests/mongodb-panache/pom.xml +++ b/integration-tests/mongodb-panache/pom.xml @@ -59,8 +59,8 @@ test - de.flapdoodle.embed - de.flapdoodle.embed.mongo + io.quarkus + quarkus-test-mongodb test diff --git a/integration-tests/mongodb-panache/src/main/resources/application.properties b/integration-tests/mongodb-panache/src/main/resources/application.properties index 9f43c244b3c3d..6a25930fdcb89 100644 --- a/integration-tests/mongodb-panache/src/main/resources/application.properties +++ b/integration-tests/mongodb-panache/src/main/resources/application.properties @@ -1,9 +1,9 @@ -quarkus.mongodb.connection-string=mongodb://localhost:27018,localhost:27019 +quarkus.mongodb.connection-string=mongodb://localhost:27017,localhost:27018 quarkus.mongodb.write-concern.journal=false quarkus.mongodb.database=books # fake a different MongoDB instance -quarkus.mongodb.cl2.connection-string=mongodb://localhost:27018,localhost:27019 +quarkus.mongodb.cl2.connection-string=mongodb://localhost:27017,localhost:27018 quarkus.mongodb.cl2.write-concern.journal=false #quarkus.log.category."io.quarkus.mongodb.panache.runtime".level=DEBUG diff --git a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongoTestResource.java b/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongoTestResource.java deleted file mode 100644 index edb722fae8fd3..0000000000000 --- a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongoTestResource.java +++ /dev/null @@ -1,86 +0,0 @@ -package io.quarkus.it.mongodb.panache; - -import java.util.Collections; -import java.util.Map; - -import org.jboss.logging.Logger; - -import de.flapdoodle.embed.mongo.Command; -import de.flapdoodle.embed.mongo.MongodExecutable; -import de.flapdoodle.embed.mongo.MongodStarter; -import de.flapdoodle.embed.mongo.config.IMongodConfig; -import de.flapdoodle.embed.mongo.config.MongodConfigBuilder; -import de.flapdoodle.embed.mongo.config.Net; -import de.flapdoodle.embed.mongo.config.RuntimeConfigBuilder; -import de.flapdoodle.embed.mongo.distribution.Version; -import de.flapdoodle.embed.process.config.IRuntimeConfig; -import de.flapdoodle.embed.process.config.io.ProcessOutput; -import de.flapdoodle.embed.process.runtime.Network; -import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; - -public class MongoTestResource implements QuarkusTestResourceLifecycleManager { - - private static final Logger LOGGER = Logger.getLogger(MongoTestResource.class); - private static MongodExecutable MONGO; - - @Override - public Map start() { - try { - //JDK bug workaround - //https://github.com/quarkusio/quarkus/issues/14424 - //force class init to prevent possible deadlock when done by mongo threads - Class.forName("sun.net.ext.ExtendedSocketOptions", true, ClassLoader.getSystemClassLoader()); - } catch (ClassNotFoundException e) { - } - try { - Version.Main version = Version.Main.V4_0; - int port = 27018; - LOGGER.infof("Starting Mongo %s on port %s", version, port); - IMongodConfig config = new MongodConfigBuilder() - .version(version) - .net(new Net(port, Network.localhostIsIPv6())) - .build(); - MONGO = getMongodExecutable(config); - try { - MONGO.start(); - } catch (Exception e) { - //every so often mongo fails to start on CI runs - //see if this helps - Thread.sleep(1000); - MONGO.start(); - } - return Collections.emptyMap(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private MongodExecutable getMongodExecutable(IMongodConfig config) { - try { - return doGetExecutable(config); - } catch (Exception e) { - // sometimes the download process can timeout so just sleep and try again - try { - Thread.sleep(1000); - } catch (InterruptedException ignored) { - - } - return doGetExecutable(config); - } - } - - private MongodExecutable doGetExecutable(IMongodConfig config) { - IRuntimeConfig runtimeConfig = new RuntimeConfigBuilder() - .defaults(Command.MongoD) - .processOutput(ProcessOutput.getDefaultInstanceSilent()) - .build(); - return MongodStarter.getInstance(runtimeConfig).prepare(config); - } - - @Override - public void stop() { - if (MONGO != null) { - MONGO.stop(); - } - } -} diff --git a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongodbPanacheMockingTest.java b/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongodbPanacheMockingTest.java index 6b8a00aba4f65..0eea1c3d48342 100644 --- a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongodbPanacheMockingTest.java +++ b/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongodbPanacheMockingTest.java @@ -19,6 +19,7 @@ import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.junit.mockito.InjectMock; +import io.quarkus.test.mongodb.MongoReplicaSetTestResource; @QuarkusTest @QuarkusTestResource(MongoReplicaSetTestResource.class) diff --git a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongodbPanacheResourceTest.java b/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongodbPanacheResourceTest.java index cef77a352c734..5b9abda1c8d92 100644 --- a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongodbPanacheResourceTest.java +++ b/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongodbPanacheResourceTest.java @@ -24,6 +24,7 @@ import io.quarkus.it.mongodb.panache.person.Person; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.mongodb.MongoReplicaSetTestResource; import io.restassured.RestAssured; import io.restassured.common.mapper.TypeRef; import io.restassured.config.ObjectMapperConfig; diff --git a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/reactive/ReactiveMongodbPanacheMockingTest.java b/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/reactive/ReactiveMongodbPanacheMockingTest.java index f9724c17059c7..4ad6cc02023b2 100644 --- a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/reactive/ReactiveMongodbPanacheMockingTest.java +++ b/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/reactive/ReactiveMongodbPanacheMockingTest.java @@ -11,13 +11,13 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; -import io.quarkus.it.mongodb.panache.MongoReplicaSetTestResource; import io.quarkus.it.mongodb.panache.reactive.person.MockableReactivePersonRepository; import io.quarkus.it.mongodb.panache.reactive.person.ReactivePersonEntity; import io.quarkus.panache.mock.PanacheMock; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.junit.mockito.InjectMock; +import io.quarkus.test.mongodb.MongoReplicaSetTestResource; import io.smallrye.mutiny.Uni; @QuarkusTest diff --git a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/reactive/ReactiveMongodbPanacheResourceTest.java b/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/reactive/ReactiveMongodbPanacheResourceTest.java index 13d238c4ac288..d3b20fcacdab8 100644 --- a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/reactive/ReactiveMongodbPanacheResourceTest.java +++ b/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/reactive/ReactiveMongodbPanacheResourceTest.java @@ -29,11 +29,11 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import io.quarkus.it.mongodb.panache.BookDTO; -import io.quarkus.it.mongodb.panache.MongoReplicaSetTestResource; import io.quarkus.it.mongodb.panache.book.BookDetail; import io.quarkus.it.mongodb.panache.person.Person; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.mongodb.MongoReplicaSetTestResource; import io.restassured.RestAssured; import io.restassured.common.mapper.TypeRef; import io.restassured.config.ObjectMapperConfig; diff --git a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/transaction/MongodbPanacheTransactionTest.java b/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/transaction/MongodbPanacheTransactionTest.java index 25e2a9b05c5ca..12e76f909e873 100644 --- a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/transaction/MongodbPanacheTransactionTest.java +++ b/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/transaction/MongodbPanacheTransactionTest.java @@ -12,9 +12,9 @@ import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import io.quarkus.it.mongodb.panache.MongoReplicaSetTestResource; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.mongodb.MongoReplicaSetTestResource; import io.restassured.RestAssured; import io.restassured.common.mapper.TypeRef; import io.restassured.config.ObjectMapperConfig; diff --git a/integration-tests/mongodb-rest-data-panache/pom.xml b/integration-tests/mongodb-rest-data-panache/pom.xml index 24ddc039a3398..5db7bba03d433 100644 --- a/integration-tests/mongodb-rest-data-panache/pom.xml +++ b/integration-tests/mongodb-rest-data-panache/pom.xml @@ -36,6 +36,11 @@ rest-assured test + + io.quarkus + quarkus-test-mongodb + test + diff --git a/integration-tests/mongodb-rest-data-panache/src/main/resources/application.properties b/integration-tests/mongodb-rest-data-panache/src/main/resources/application.properties index 1662de97aef85..d7e6302e19151 100644 --- a/integration-tests/mongodb-rest-data-panache/src/main/resources/application.properties +++ b/integration-tests/mongodb-rest-data-panache/src/main/resources/application.properties @@ -1,2 +1,3 @@ +quarkus.mongodb.connection-string=mongodb://localhost:27017 quarkus.mongodb.write-concern.journal=false quarkus.mongodb.database=test diff --git a/integration-tests/mongodb-rest-data-panache/src/test/java/io/quarkus/it/mongodb/rest/data/panache/MongoDbRestDataPanacheTest.java b/integration-tests/mongodb-rest-data-panache/src/test/java/io/quarkus/it/mongodb/rest/data/panache/MongoDbRestDataPanacheTest.java index 05417efbf3b55..f857c7d8b3776 100644 --- a/integration-tests/mongodb-rest-data-panache/src/test/java/io/quarkus/it/mongodb/rest/data/panache/MongoDbRestDataPanacheTest.java +++ b/integration-tests/mongodb-rest-data-panache/src/test/java/io/quarkus/it/mongodb/rest/data/panache/MongoDbRestDataPanacheTest.java @@ -18,10 +18,13 @@ import org.junit.jupiter.api.condition.DisabledOnOs; import org.junit.jupiter.api.condition.OS; +import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.mongodb.MongoTestResource; import io.restassured.response.Response; @QuarkusTest +@QuarkusTestResource(MongoTestResource.class) @DisabledOnOs(OS.WINDOWS) class MongoDbRestDataPanacheTest { diff --git a/test-framework/mongodb/pom.xml b/test-framework/mongodb/pom.xml new file mode 100644 index 0000000000000..76597cf209d21 --- /dev/null +++ b/test-framework/mongodb/pom.xml @@ -0,0 +1,33 @@ + + + + io.quarkus + quarkus-test-framework + 999-SNAPSHOT + + 4.0.0 + + quarkus-test-mongodb + Quarkus - Test Framework - MongoDB Support + + + io.quarkus + quarkus-test-common + + + io.quarkus + quarkus-mongodb-client + + + de.flapdoodle.embed + de.flapdoodle.embed.mongo + + + org.awaitility + awaitility + + + + \ No newline at end of file diff --git a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongoReplicaSetTestResource.java b/test-framework/mongodb/src/main/java/io/quarkus/test/mongodb/MongoReplicaSetTestResource.java similarity index 92% rename from integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongoReplicaSetTestResource.java rename to test-framework/mongodb/src/main/java/io/quarkus/test/mongodb/MongoReplicaSetTestResource.java index 3e8f4f465fa52..d089b2bb140d1 100644 --- a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongoReplicaSetTestResource.java +++ b/test-framework/mongodb/src/main/java/io/quarkus/test/mongodb/MongoReplicaSetTestResource.java @@ -1,4 +1,4 @@ -package io.quarkus.it.mongodb.panache; +package io.quarkus.test.mongodb; import static org.awaitility.Awaitility.await; @@ -10,6 +10,7 @@ import java.util.Map; import java.util.concurrent.TimeUnit; +import org.awaitility.Awaitility; import org.bson.Document; import org.jboss.logging.Logger; @@ -36,10 +37,17 @@ public class MongoReplicaSetTestResource implements QuarkusTestResourceLifecycle @Override public Map start() { + try { + //JDK bug workaround + //https://github.com/quarkusio/quarkus/issues/14424 + //force class init to prevent possible deadlock when done by mongo threads + Class.forName("sun.net.ext.ExtendedSocketOptions", true, ClassLoader.getSystemClassLoader()); + } catch (ClassNotFoundException e) { + } try { List configs = new ArrayList<>(); for (int i = 0; i < 2; i++) { - int port = 27018 + i; + int port = 27017 + i; configs.add(buildMongodConfiguration("localhost", port, true)); } configs.forEach(config -> { @@ -90,7 +98,7 @@ private static void initializeReplicaSet(final List mongodConfigL LOGGER.infof("replSetInitiate: %s", cr); // Check replica set status before to proceed - await() + Awaitility.await() .pollInterval(100, TimeUnit.MILLISECONDS) .atMost(1, TimeUnit.MINUTES) .until(() -> { diff --git a/integration-tests/mongodb-client/src/test/java/io/quarkus/it/mongodb/MongoTestResource.java b/test-framework/mongodb/src/main/java/io/quarkus/test/mongodb/MongoTestResource.java similarity index 98% rename from integration-tests/mongodb-client/src/test/java/io/quarkus/it/mongodb/MongoTestResource.java rename to test-framework/mongodb/src/main/java/io/quarkus/test/mongodb/MongoTestResource.java index 01513ad858ecb..c4cb1b51cbeb3 100644 --- a/integration-tests/mongodb-client/src/test/java/io/quarkus/it/mongodb/MongoTestResource.java +++ b/test-framework/mongodb/src/main/java/io/quarkus/test/mongodb/MongoTestResource.java @@ -1,4 +1,4 @@ -package io.quarkus.it.mongodb; +package io.quarkus.test.mongodb; import java.io.IOException; import java.util.Collections; @@ -35,7 +35,7 @@ public Map start() { } try { Version.Main version = Version.Main.V4_0; - int port = 27018; + int port = 27017; LOGGER.infof("Starting Mongo %s on port %s", version, port); IMongodConfig config = new MongodConfigBuilder() .version(version) diff --git a/test-framework/pom.xml b/test-framework/pom.xml index 224d4de657a68..c626f59b6f519 100644 --- a/test-framework/pom.xml +++ b/test-framework/pom.xml @@ -40,6 +40,7 @@ oidc-server keycloak-server jacoco + mongodb From 6bcbd8d7794e7bf81b58e2c34e2b8ae8abe19b7f Mon Sep 17 00:00:00 2001 From: Kevin Wooten Date: Wed, 5 May 2021 10:55:38 -0700 Subject: [PATCH 0070/2077] Fixes VaultTransitSecretEngine.readKey to work with symmetric & asymmetric keys This fixes the current failure to read asymmetric keys while adding more information in a backwards compatible and futue proof format. Fixes #16988 * Changes `VaultTransitReadKeyData.keys` to be a list of `VaultTransitKeyVersionData`(which can contain any key data) * Uses custom deserializer on `VaultTransitReadKeyData.keys` to allow `VaultTransitKeyVersionData` values to be deserialized from an integer timestamp or a map of info values. * Added missing `latest_version`, `min_available_version` and `type` fields to `VaultTransitReadKeyData` * Made `VaultTransitKeyDetail` abstract, subclasses for symmetric (`VaultTransitSymmetricKeyDetail`) and asymmetric (`VaultTransitAsymmetricKeyDetail`) keys are provided. * Added abstract `versions` property to `VaultTransitKeyDetail` which is a `Map`, subclasses of `VaultTransitKeyDetail` provide a concrete `versions` property with an unambiguous type. * * E.g. `VaultTransitAsymmetricKeyDetail.versions` is defined as `Map` * * Allows users to test the key detail type once (via `instanceof`) and downcast to a detailt type that has a specifically typed list of versions. * `VaultTransitKeyVersion` is abstract also, with subclasses for asymmetric (`VaultTransitAsymmetricKeyVersion`) and symmetric (`VaultTransitSymmetricKeyVersion`) keys * Added `latestVersion`, `minAvailableVersion` and `type` properties to `VaultTransitKeyDetail` * Changes are additive and therefore backwards compatible * Deprecates the `keys` property as `versions` provides the same information in a more easily accessible format and is future proof for adding more properties as Vault makes changes to the API. * Added integration test cases for reading ECDSA, RSA and AES keys * Added `JavaTimeModule` to the mapper used for vault responses. --- extensions/vault/model/pom.xml | 5 + .../transit/VaultTransitKeyVersionData.java | 41 ++++ .../dto/transit/VaultTransitReadKeyData.java | 9 +- .../quarkus/vault/VaultTransitKeyDetail.java | 137 ------------- .../vault/VaultTransitSecretEngine.java | 4 +- .../vault/runtime/VaultTransitManager.java | 50 ++++- .../runtime/client/VertxVaultClient.java | 3 +- .../VaultTransitAsymmetricKeyDetail.java | 4 + .../VaultTransitAsymmetricKeyVersion.java | 25 +++ .../VaultTransitExportKeyType.java | 2 +- .../vault/transit/VaultTransitKeyDetail.java | 185 ++++++++++++++++++ .../vault/transit/VaultTransitKeyVersion.java | 17 ++ .../VaultTransitSymmetricKeyDetail.java | 4 + .../VaultTransitSymmetricKeyVersion.java | 4 + .../io/quarkus/it/vault/VaultTestService.java | 2 +- .../io/quarkus/vault/VaultTransitITCase.java | 120 +++++++++++- 16 files changed, 463 insertions(+), 149 deletions(-) create mode 100644 extensions/vault/model/src/main/java/io/quarkus/vault/runtime/client/dto/transit/VaultTransitKeyVersionData.java delete mode 100644 extensions/vault/runtime/src/main/java/io/quarkus/vault/VaultTransitKeyDetail.java create mode 100644 extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitAsymmetricKeyDetail.java create mode 100644 extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitAsymmetricKeyVersion.java rename extensions/vault/runtime/src/main/java/io/quarkus/vault/{ => transit}/VaultTransitExportKeyType.java (79%) create mode 100644 extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitKeyDetail.java create mode 100644 extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitKeyVersion.java create mode 100644 extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitSymmetricKeyDetail.java create mode 100644 extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitSymmetricKeyVersion.java diff --git a/extensions/vault/model/pom.xml b/extensions/vault/model/pom.xml index 59b984306018c..517fb87c71931 100644 --- a/extensions/vault/model/pom.xml +++ b/extensions/vault/model/pom.xml @@ -25,6 +25,11 @@ quarkus-jackson + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + diff --git a/extensions/vault/model/src/main/java/io/quarkus/vault/runtime/client/dto/transit/VaultTransitKeyVersionData.java b/extensions/vault/model/src/main/java/io/quarkus/vault/runtime/client/dto/transit/VaultTransitKeyVersionData.java new file mode 100644 index 0000000000000..96698bbaf9f38 --- /dev/null +++ b/extensions/vault/model/src/main/java/io/quarkus/vault/runtime/client/dto/transit/VaultTransitKeyVersionData.java @@ -0,0 +1,41 @@ +package io.quarkus.vault.runtime.client.dto.transit; + +import java.io.IOException; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; + +import io.quarkus.vault.runtime.client.dto.VaultModel; + +public class VaultTransitKeyVersionData implements VaultModel { + + public String name; + @JsonProperty("creation_time") + public OffsetDateTime creationTime; + @JsonProperty("public_key") + public String publicKey; + + static class Deserializer extends JsonDeserializer { + + Deserializer() { + } + + @Override + public VaultTransitKeyVersionData deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + if (p.hasToken(JsonToken.VALUE_NUMBER_INT)) { + long timestamp = p.readValueAs(Long.class); + VaultTransitKeyVersionData data = new VaultTransitKeyVersionData(); + data.creationTime = Instant.ofEpochSecond(timestamp).atOffset(ZoneOffset.UTC); + return data; + } else { + return p.readValueAs(VaultTransitKeyVersionData.class); + } + } + } +} diff --git a/extensions/vault/model/src/main/java/io/quarkus/vault/runtime/client/dto/transit/VaultTransitReadKeyData.java b/extensions/vault/model/src/main/java/io/quarkus/vault/runtime/client/dto/transit/VaultTransitReadKeyData.java index 5f619fe81d64c..d4ca3f3a31750 100644 --- a/extensions/vault/model/src/main/java/io/quarkus/vault/runtime/client/dto/transit/VaultTransitReadKeyData.java +++ b/extensions/vault/model/src/main/java/io/quarkus/vault/runtime/client/dto/transit/VaultTransitReadKeyData.java @@ -3,6 +3,7 @@ import java.util.Map; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import io.quarkus.vault.runtime.client.dto.VaultModel; @@ -15,7 +16,12 @@ public class VaultTransitReadKeyData implements VaultModel { public boolean exportable; @JsonProperty(value = "allow_plaintext_backup") public boolean allowPlaintextBackup; - public Map keys; + @JsonDeserialize(contentUsing = VaultTransitKeyVersionData.Deserializer.class) + public Map keys; + @JsonProperty(value = "latest_version") + public int latestVersion; + @JsonProperty(value = "min_available_version") + public int minAvailableVersion; @JsonProperty(value = "min_decryption_version") public int minDecryptionVersion; @JsonProperty(value = "min_encryption_version") @@ -29,4 +35,5 @@ public class VaultTransitReadKeyData implements VaultModel { public boolean supportsDerivation; @JsonProperty(value = "supports_signing") public boolean supportsSigning; + public String type; } diff --git a/extensions/vault/runtime/src/main/java/io/quarkus/vault/VaultTransitKeyDetail.java b/extensions/vault/runtime/src/main/java/io/quarkus/vault/VaultTransitKeyDetail.java deleted file mode 100644 index a995d2c314812..0000000000000 --- a/extensions/vault/runtime/src/main/java/io/quarkus/vault/VaultTransitKeyDetail.java +++ /dev/null @@ -1,137 +0,0 @@ -package io.quarkus.vault; - -import java.util.Map; - -public class VaultTransitKeyDetail { - - private String name; - private String detail; - private boolean deletionAllowed; - private boolean derived; - private boolean exportable; - private boolean allowPlaintextBackup; - private Map keys; - private int minDecryptionVersion; - private int minEncryptionVersion; - private boolean supportsEncryption; - private boolean supportsDecryption; - private boolean supportsDerivation; - private boolean supportsSigning; - - public String getName() { - return name; - } - - public VaultTransitKeyDetail setName(String name) { - this.name = name; - return this; - } - - public String getDetail() { - return detail; - } - - public VaultTransitKeyDetail setDetail(String detail) { - this.detail = detail; - return this; - } - - public boolean isDeletionAllowed() { - return deletionAllowed; - } - - public VaultTransitKeyDetail setDeletionAllowed(boolean deletionAllowed) { - this.deletionAllowed = deletionAllowed; - return this; - } - - public boolean isDerived() { - return derived; - } - - public VaultTransitKeyDetail setDerived(boolean derived) { - this.derived = derived; - return this; - } - - public boolean isExportable() { - return exportable; - } - - public VaultTransitKeyDetail setExportable(boolean exportable) { - this.exportable = exportable; - return this; - } - - public boolean isAllowPlaintextBackup() { - return allowPlaintextBackup; - } - - public VaultTransitKeyDetail setAllowPlaintextBackup(boolean allowPlaintextBackup) { - this.allowPlaintextBackup = allowPlaintextBackup; - return this; - } - - public Map getKeys() { - return keys; - } - - public VaultTransitKeyDetail setKeys(Map keys) { - this.keys = keys; - return this; - } - - public int getMinDecryptionVersion() { - return minDecryptionVersion; - } - - public VaultTransitKeyDetail setMinDecryptionVersion(int minDecryptionVersion) { - this.minDecryptionVersion = minDecryptionVersion; - return this; - } - - public int getMinEncryptionVersion() { - return minEncryptionVersion; - } - - public VaultTransitKeyDetail setMinEncryptionVersion(int minEncryptionVersion) { - this.minEncryptionVersion = minEncryptionVersion; - return this; - } - - public boolean isSupportsEncryption() { - return supportsEncryption; - } - - public VaultTransitKeyDetail setSupportsEncryption(boolean supportsEncryption) { - this.supportsEncryption = supportsEncryption; - return this; - } - - public boolean isSupportsDecryption() { - return supportsDecryption; - } - - public VaultTransitKeyDetail setSupportsDecryption(boolean supportsDecryption) { - this.supportsDecryption = supportsDecryption; - return this; - } - - public boolean isSupportsDerivation() { - return supportsDerivation; - } - - public VaultTransitKeyDetail setSupportsDerivation(boolean supportsDerivation) { - this.supportsDerivation = supportsDerivation; - return this; - } - - public boolean isSupportsSigning() { - return supportsSigning; - } - - public VaultTransitKeyDetail setSupportsSigning(boolean supportsSigning) { - this.supportsSigning = supportsSigning; - return this; - } -} diff --git a/extensions/vault/runtime/src/main/java/io/quarkus/vault/VaultTransitSecretEngine.java b/extensions/vault/runtime/src/main/java/io/quarkus/vault/VaultTransitSecretEngine.java index 1c81fe9cfc85e..1a753889db5c1 100644 --- a/extensions/vault/runtime/src/main/java/io/quarkus/vault/VaultTransitSecretEngine.java +++ b/extensions/vault/runtime/src/main/java/io/quarkus/vault/VaultTransitSecretEngine.java @@ -17,6 +17,8 @@ import io.quarkus.vault.transit.VaultEncryptionBatchException; import io.quarkus.vault.transit.VaultRewrappingBatchException; import io.quarkus.vault.transit.VaultSigningBatchException; +import io.quarkus.vault.transit.VaultTransitExportKeyType; +import io.quarkus.vault.transit.VaultTransitKeyDetail; import io.quarkus.vault.transit.VaultTransitKeyExportDetail; import io.quarkus.vault.transit.VaultVerificationBatchException; import io.quarkus.vault.transit.VerificationRequest; @@ -313,7 +315,7 @@ void verifySignature(String keyName, String signature, SigningInput input, SignV * @return key detail, or null if the key does not exist * @see read key */ - VaultTransitKeyDetail readKey(String keyName); + VaultTransitKeyDetail readKey(String keyName); /** * List all Transit keys. diff --git a/extensions/vault/runtime/src/main/java/io/quarkus/vault/runtime/VaultTransitManager.java b/extensions/vault/runtime/src/main/java/io/quarkus/vault/runtime/VaultTransitManager.java index 93a629dc8a061..be33e3e609afa 100644 --- a/extensions/vault/runtime/src/main/java/io/quarkus/vault/runtime/VaultTransitManager.java +++ b/extensions/vault/runtime/src/main/java/io/quarkus/vault/runtime/VaultTransitManager.java @@ -12,15 +12,15 @@ import java.util.IdentityHashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.function.Function; +import java.util.stream.Collectors; import java.util.stream.IntStream; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; import io.quarkus.vault.VaultException; -import io.quarkus.vault.VaultTransitExportKeyType; -import io.quarkus.vault.VaultTransitKeyDetail; import io.quarkus.vault.VaultTransitSecretEngine; import io.quarkus.vault.runtime.client.VaultClientException; import io.quarkus.vault.runtime.client.dto.transit.VaultTransitCreateKeyBody; @@ -34,6 +34,7 @@ import io.quarkus.vault.runtime.client.dto.transit.VaultTransitEncryptDataBatchResult; import io.quarkus.vault.runtime.client.dto.transit.VaultTransitKeyConfigBody; import io.quarkus.vault.runtime.client.dto.transit.VaultTransitKeyExport; +import io.quarkus.vault.runtime.client.dto.transit.VaultTransitKeyVersionData; import io.quarkus.vault.runtime.client.dto.transit.VaultTransitReadKeyData; import io.quarkus.vault.runtime.client.dto.transit.VaultTransitRewrapBatchInput; import io.quarkus.vault.runtime.client.dto.transit.VaultTransitRewrapBody; @@ -67,7 +68,13 @@ import io.quarkus.vault.transit.VaultEncryptionBatchException; import io.quarkus.vault.transit.VaultRewrappingBatchException; import io.quarkus.vault.transit.VaultSigningBatchException; +import io.quarkus.vault.transit.VaultTransitAsymmetricKeyDetail; +import io.quarkus.vault.transit.VaultTransitAsymmetricKeyVersion; +import io.quarkus.vault.transit.VaultTransitExportKeyType; +import io.quarkus.vault.transit.VaultTransitKeyDetail; import io.quarkus.vault.transit.VaultTransitKeyExportDetail; +import io.quarkus.vault.transit.VaultTransitSymmetricKeyDetail; +import io.quarkus.vault.transit.VaultTransitSymmetricKeyVersion; import io.quarkus.vault.transit.VaultVerificationBatchException; import io.quarkus.vault.transit.VerificationRequest; @@ -395,7 +402,7 @@ public VaultTransitKeyExportDetail exportKey(String keyName, VaultTransitExportK } @Override - public VaultTransitKeyDetail readKey(String keyName) { + public VaultTransitKeyDetail readKey(String keyName) { try { return map(vaultInternalTransitSecretEngine.readTransitKey(getToken(), keyName).data); } catch (VaultClientException e) { @@ -412,14 +419,27 @@ public List listKeys() { return vaultInternalTransitSecretEngine.listTransitKeys(getToken()).data.keys; } - protected VaultTransitKeyDetail map(VaultTransitReadKeyData data) { - VaultTransitKeyDetail result = new VaultTransitKeyDetail(); + protected VaultTransitKeyDetail map(VaultTransitReadKeyData data) { + VaultTransitKeyVersionData latestVersionData = data.keys.get(Integer.toString(data.latestVersion)); + VaultTransitKeyDetail result; + if (latestVersionData.publicKey != null) { + Map versions = data.keys.entrySet().stream() + .collect(Collectors.toMap(Entry::getKey, VaultTransitManager::mapAsymmetricKeyVersion)); + result = new VaultTransitAsymmetricKeyDetail() + .setVersions(versions); + } else { + Map versions = data.keys.entrySet().stream() + .collect(Collectors.toMap(Entry::getKey, VaultTransitManager::mapSymmetricKeyVersion)); + result = new VaultTransitSymmetricKeyDetail() + .setVersions(versions); + } result.setDetail(data.detail); result.setDeletionAllowed(data.deletionAllowed); result.setDerived(data.derived); result.setExportable(data.exportable); result.setAllowPlaintextBackup(data.allowPlaintextBackup); - result.setKeys(data.keys); + result.setLatestVersion(data.latestVersion); + result.setMinAvailableVersion(data.minAvailableVersion); result.setMinDecryptionVersion(data.minDecryptionVersion); result.setMinEncryptionVersion(data.minEncryptionVersion); result.setName(data.name); @@ -427,9 +447,27 @@ protected VaultTransitKeyDetail map(VaultTransitReadKeyData data) { result.setSupportsDecryption(data.supportsDecryption); result.setSupportsDerivation(data.supportsDerivation); result.setSupportsSigning(data.supportsSigning); + result.setType(data.type); return result; } + private static VaultTransitAsymmetricKeyVersion mapAsymmetricKeyVersion( + Map.Entry entry) { + VaultTransitKeyVersionData data = entry.getValue(); + VaultTransitAsymmetricKeyVersion version = new VaultTransitAsymmetricKeyVersion(); + version.setName(data.name); + version.setPublicKey(data.publicKey); + version.setCreationTime(data.creationTime); + return version; + } + + private static VaultTransitSymmetricKeyVersion mapSymmetricKeyVersion(Map.Entry entry) { + VaultTransitKeyVersionData data = entry.getValue(); + VaultTransitSymmetricKeyVersion version = new VaultTransitSymmetricKeyVersion(); + version.setCreationTime(data.creationTime); + return version; + } + // --- private void checkBatchErrors(List results, diff --git a/extensions/vault/runtime/src/main/java/io/quarkus/vault/runtime/client/VertxVaultClient.java b/extensions/vault/runtime/src/main/java/io/quarkus/vault/runtime/client/VertxVaultClient.java index 80bfdb4f3916f..9e1be387f5465 100644 --- a/extensions/vault/runtime/src/main/java/io/quarkus/vault/runtime/client/VertxVaultClient.java +++ b/extensions/vault/runtime/src/main/java/io/quarkus/vault/runtime/client/VertxVaultClient.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import io.quarkus.runtime.TlsConfig; import io.quarkus.vault.VaultException; @@ -46,7 +47,7 @@ public class VertxVaultClient implements VaultClient { private final VaultConfigHolder vaultConfigHolder; private WebClient webClient; - ObjectMapper mapper = new ObjectMapper(); + ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule()); public VertxVaultClient(VaultConfigHolder vaultConfigHolder, TlsConfig tlsConfig) { this.vaultConfigHolder = vaultConfigHolder; diff --git a/extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitAsymmetricKeyDetail.java b/extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitAsymmetricKeyDetail.java new file mode 100644 index 0000000000000..fba40d496a7cd --- /dev/null +++ b/extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitAsymmetricKeyDetail.java @@ -0,0 +1,4 @@ +package io.quarkus.vault.transit; + +public class VaultTransitAsymmetricKeyDetail extends VaultTransitKeyDetail { +} diff --git a/extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitAsymmetricKeyVersion.java b/extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitAsymmetricKeyVersion.java new file mode 100644 index 0000000000000..eafa49a19f1ff --- /dev/null +++ b/extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitAsymmetricKeyVersion.java @@ -0,0 +1,25 @@ +package io.quarkus.vault.transit; + +public class VaultTransitAsymmetricKeyVersion extends VaultTransitKeyVersion { + + private String name; + private String publicKey; + + public String getName() { + return name; + } + + public VaultTransitAsymmetricKeyVersion setName(String name) { + this.name = name; + return this; + } + + public String getPublicKey() { + return publicKey; + } + + public VaultTransitAsymmetricKeyVersion setPublicKey(String publicKey) { + this.publicKey = publicKey; + return this; + } +} diff --git a/extensions/vault/runtime/src/main/java/io/quarkus/vault/VaultTransitExportKeyType.java b/extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitExportKeyType.java similarity index 79% rename from extensions/vault/runtime/src/main/java/io/quarkus/vault/VaultTransitExportKeyType.java rename to extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitExportKeyType.java index c500d2be003ed..15a31e92722a0 100644 --- a/extensions/vault/runtime/src/main/java/io/quarkus/vault/VaultTransitExportKeyType.java +++ b/extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitExportKeyType.java @@ -1,4 +1,4 @@ -package io.quarkus.vault; +package io.quarkus.vault.transit; /** * key type used in transit key export diff --git a/extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitKeyDetail.java b/extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitKeyDetail.java new file mode 100644 index 0000000000000..5ea3d53028a43 --- /dev/null +++ b/extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitKeyDetail.java @@ -0,0 +1,185 @@ +package io.quarkus.vault.transit; + +import static java.util.stream.Collectors.toMap; + +import java.util.Map; +import java.util.Map.Entry; + +public abstract class VaultTransitKeyDetail { + + private String name; + private String detail; + private boolean deletionAllowed; + private boolean derived; + private boolean exportable; + private boolean allowPlaintextBackup; + private Map versions; + private int latestVersion; + private int minAvailableVersion; + private int minDecryptionVersion; + private int minEncryptionVersion; + private boolean supportsEncryption; + private boolean supportsDecryption; + private boolean supportsDerivation; + private boolean supportsSigning; + private String type; + + public String getName() { + return name; + } + + public VaultTransitKeyDetail setName(String name) { + this.name = name; + return this; + } + + public String getDetail() { + return detail; + } + + public VaultTransitKeyDetail setDetail(String detail) { + this.detail = detail; + return this; + } + + public boolean isDeletionAllowed() { + return deletionAllowed; + } + + public VaultTransitKeyDetail setDeletionAllowed(boolean deletionAllowed) { + this.deletionAllowed = deletionAllowed; + return this; + } + + public boolean isDerived() { + return derived; + } + + public VaultTransitKeyDetail setDerived(boolean derived) { + this.derived = derived; + return this; + } + + public boolean isExportable() { + return exportable; + } + + public VaultTransitKeyDetail setExportable(boolean exportable) { + this.exportable = exportable; + return this; + } + + public boolean isAllowPlaintextBackup() { + return allowPlaintextBackup; + } + + public VaultTransitKeyDetail setAllowPlaintextBackup(boolean allowPlaintextBackup) { + this.allowPlaintextBackup = allowPlaintextBackup; + return this; + } + + /** + * Returns a map of version numbers to Unix epoch timestamps of when the version was created. + * + * @deprecated This method has been deprecated in favor of {@link #getVersions()} which provides the same data + * via the {@link VaultTransitKeyVersion#getCreationTime()} property. + */ + @Deprecated + public Map getKeys() { + return versions.entrySet().stream() + .collect(toMap(Entry::getKey, entry -> (int) entry.getValue().getCreationTime().toEpochSecond())); + } + + /** + * Returns a map of version numbers to {@link VaultTransitKeyVersion} objects. + */ + public Map getVersions() { + return versions; + } + + public VaultTransitKeyDetail setVersions(Map versions) { + this.versions = versions; + return this; + } + + public int getLatestVersion() { + return latestVersion; + } + + public VaultTransitKeyDetail setLatestVersion(int latestVersion) { + this.latestVersion = latestVersion; + return this; + } + + public int getMinAvailableVersion() { + return minAvailableVersion; + } + + public VaultTransitKeyDetail setMinAvailableVersion(int minAvailableVersion) { + this.minAvailableVersion = minAvailableVersion; + return this; + } + + public int getMinDecryptionVersion() { + return minDecryptionVersion; + } + + public VaultTransitKeyDetail setMinDecryptionVersion(int minDecryptionVersion) { + this.minDecryptionVersion = minDecryptionVersion; + return this; + } + + public int getMinEncryptionVersion() { + return minEncryptionVersion; + } + + public VaultTransitKeyDetail setMinEncryptionVersion(int minEncryptionVersion) { + this.minEncryptionVersion = minEncryptionVersion; + return this; + } + + public boolean isSupportsEncryption() { + return supportsEncryption; + } + + public VaultTransitKeyDetail setSupportsEncryption(boolean supportsEncryption) { + this.supportsEncryption = supportsEncryption; + return this; + } + + public boolean isSupportsDecryption() { + return supportsDecryption; + } + + public VaultTransitKeyDetail setSupportsDecryption(boolean supportsDecryption) { + this.supportsDecryption = supportsDecryption; + return this; + } + + public boolean isSupportsDerivation() { + return supportsDerivation; + } + + public VaultTransitKeyDetail setSupportsDerivation(boolean supportsDerivation) { + this.supportsDerivation = supportsDerivation; + return this; + } + + public boolean isSupportsSigning() { + return supportsSigning; + } + + public VaultTransitKeyDetail setSupportsSigning(boolean supportsSigning) { + this.supportsSigning = supportsSigning; + return this; + } + + public String getType() { + return type; + } + + public VaultTransitKeyDetail setType(String type) { + this.type = type; + return this; + } +} diff --git a/extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitKeyVersion.java b/extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitKeyVersion.java new file mode 100644 index 0000000000000..bf09abab09270 --- /dev/null +++ b/extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitKeyVersion.java @@ -0,0 +1,17 @@ +package io.quarkus.vault.transit; + +import java.time.OffsetDateTime; + +public abstract class VaultTransitKeyVersion { + + private OffsetDateTime creationTime; + + public OffsetDateTime getCreationTime() { + return creationTime; + } + + public VaultTransitKeyVersion setCreationTime(OffsetDateTime creationTime) { + this.creationTime = creationTime; + return this; + } +} diff --git a/extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitSymmetricKeyDetail.java b/extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitSymmetricKeyDetail.java new file mode 100644 index 0000000000000..5e989f6c02f2a --- /dev/null +++ b/extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitSymmetricKeyDetail.java @@ -0,0 +1,4 @@ +package io.quarkus.vault.transit; + +public class VaultTransitSymmetricKeyDetail extends VaultTransitKeyDetail { +} diff --git a/extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitSymmetricKeyVersion.java b/extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitSymmetricKeyVersion.java new file mode 100644 index 0000000000000..955945d0976a9 --- /dev/null +++ b/extensions/vault/runtime/src/main/java/io/quarkus/vault/transit/VaultTransitSymmetricKeyVersion.java @@ -0,0 +1,4 @@ +package io.quarkus.vault.transit; + +public class VaultTransitSymmetricKeyVersion extends VaultTransitKeyVersion { +} diff --git a/integration-tests/vault-app/src/main/java/io/quarkus/it/vault/VaultTestService.java b/integration-tests/vault-app/src/main/java/io/quarkus/it/vault/VaultTestService.java index 430aa29cf9582..43b6e10c1cf4c 100644 --- a/integration-tests/vault-app/src/main/java/io/quarkus/it/vault/VaultTestService.java +++ b/integration-tests/vault-app/src/main/java/io/quarkus/it/vault/VaultTestService.java @@ -15,13 +15,13 @@ import org.jboss.logging.Logger; import io.quarkus.vault.VaultKVSecretEngine; -import io.quarkus.vault.VaultTransitExportKeyType; import io.quarkus.vault.VaultTransitSecretEngine; import io.quarkus.vault.runtime.client.VaultClientException; import io.quarkus.vault.transit.ClearData; import io.quarkus.vault.transit.KeyConfigRequestDetail; import io.quarkus.vault.transit.KeyCreationRequestDetail; import io.quarkus.vault.transit.SigningInput; +import io.quarkus.vault.transit.VaultTransitExportKeyType; @ApplicationScoped public class VaultTestService { diff --git a/integration-tests/vault/src/test/java/io/quarkus/vault/VaultTransitITCase.java b/integration-tests/vault/src/test/java/io/quarkus/vault/VaultTransitITCase.java index 9b92b3a7f00d0..5425507ed0084 100644 --- a/integration-tests/vault/src/test/java/io/quarkus/vault/VaultTransitITCase.java +++ b/integration-tests/vault/src/test/java/io/quarkus/vault/VaultTransitITCase.java @@ -1,17 +1,18 @@ package io.quarkus.vault; -import static io.quarkus.vault.VaultTransitExportKeyType.encryption; import static io.quarkus.vault.test.VaultTestExtension.ENCRYPTION_DERIVED_KEY_NAME; import static io.quarkus.vault.test.VaultTestExtension.ENCRYPTION_KEY2_NAME; import static io.quarkus.vault.test.VaultTestExtension.ENCRYPTION_KEY_NAME; import static io.quarkus.vault.test.VaultTestExtension.SIGN_DERIVATION_KEY_NAME; import static io.quarkus.vault.test.VaultTestExtension.SIGN_KEY2_NAME; import static io.quarkus.vault.test.VaultTestExtension.SIGN_KEY_NAME; +import static io.quarkus.vault.transit.VaultTransitExportKeyType.encryption; import static io.quarkus.vault.transit.VaultTransitSecretEngineConstants.INVALID_SIGNATURE; import static java.util.Collections.singletonList; import static java.util.stream.Collectors.toList; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -43,7 +44,12 @@ import io.quarkus.vault.transit.SigningInput; import io.quarkus.vault.transit.SigningRequest; import io.quarkus.vault.transit.TransitContext; +import io.quarkus.vault.transit.VaultTransitAsymmetricKeyDetail; +import io.quarkus.vault.transit.VaultTransitAsymmetricKeyVersion; +import io.quarkus.vault.transit.VaultTransitKeyDetail; import io.quarkus.vault.transit.VaultTransitKeyExportDetail; +import io.quarkus.vault.transit.VaultTransitSymmetricKeyDetail; +import io.quarkus.vault.transit.VaultTransitSymmetricKeyVersion; import io.quarkus.vault.transit.VaultVerificationBatchException; import io.quarkus.vault.transit.VerificationRequest; @@ -360,6 +366,8 @@ public void adminKey() { assertTrue(mykey.isSupportsDerivation()); assertEquals(1, mykey.getKeys().size()); assertTrue(mykey.getKeys().containsKey("1")); + assertEquals(1, mykey.getVersions().size()); + assertTrue(mykey.getVersions().containsKey("1")); assertEquals(1, mykey.getMinDecryptionVersion()); assertEquals(0, mykey.getMinEncryptionVersion()); @@ -376,4 +384,114 @@ public void adminKey() { assertNull(transitSecretEngine.readKey(KEY_NAME)); } + @Test + public void asymmetricReadECDSAKey() { + + assertFalse(transitSecretEngine.listKeys().contains(KEY_NAME)); + transitSecretEngine.createKey(KEY_NAME, new KeyCreationRequestDetail().setType("ecdsa-p256")); + assertTrue(transitSecretEngine.listKeys().contains(KEY_NAME)); + + VaultTransitKeyDetail mykey = transitSecretEngine.readKey(KEY_NAME); + assertTrue(mykey instanceof VaultTransitAsymmetricKeyDetail); + assertEquals(KEY_NAME, mykey.getName()); + assertFalse(mykey.isExportable()); + assertFalse(mykey.isDeletionAllowed()); + assertFalse(mykey.isSupportsDecryption()); + assertFalse(mykey.isSupportsEncryption()); + assertFalse(mykey.isSupportsDerivation()); + assertTrue(mykey.isSupportsSigning()); + assertEquals(mykey.getType(), "ecdsa-p256"); + assertEquals(1, mykey.getKeys().size()); + assertTrue(mykey.getKeys().containsKey("1")); + assertEquals(1, mykey.getVersions().size()); + assertTrue(mykey.getVersions().containsKey("1")); + assertNotNull(mykey.getVersions().get("1").getCreationTime()); + assertTrue(mykey.getVersions().get("1") instanceof VaultTransitAsymmetricKeyVersion); + assertNotNull(((VaultTransitAsymmetricKeyVersion) mykey.getVersions().get("1")).getPublicKey()); + assertEquals(1, mykey.getLatestVersion()); + assertEquals(0, mykey.getMinAvailableVersion()); + assertEquals(1, mykey.getMinDecryptionVersion()); + assertEquals(0, mykey.getMinEncryptionVersion()); + + transitSecretEngine.updateKeyConfiguration(KEY_NAME, new KeyConfigRequestDetail().setDeletionAllowed(true)); + mykey = transitSecretEngine.readKey(KEY_NAME); + assertTrue(mykey.isDeletionAllowed()); + + transitSecretEngine.deleteKey(KEY_NAME); + assertNull(transitSecretEngine.readKey(KEY_NAME)); + } + + @Test + public void asymmetricReadRSAKey() { + + assertFalse(transitSecretEngine.listKeys().contains(KEY_NAME)); + transitSecretEngine.createKey(KEY_NAME, new KeyCreationRequestDetail().setType("rsa-2048")); + assertTrue(transitSecretEngine.listKeys().contains(KEY_NAME)); + + VaultTransitKeyDetail mykey = transitSecretEngine.readKey(KEY_NAME); + assertTrue(mykey instanceof VaultTransitAsymmetricKeyDetail); + assertEquals(KEY_NAME, mykey.getName()); + assertFalse(mykey.isExportable()); + assertFalse(mykey.isDeletionAllowed()); + assertTrue(mykey.isSupportsDecryption()); + assertTrue(mykey.isSupportsEncryption()); + assertFalse(mykey.isSupportsDerivation()); + assertTrue(mykey.isSupportsSigning()); + assertEquals("rsa-2048", mykey.getType()); + assertEquals(1, mykey.getKeys().size()); + assertTrue(mykey.getKeys().containsKey("1")); + assertEquals(1, mykey.getVersions().size()); + assertTrue(mykey.getVersions().containsKey("1")); + assertNotNull(mykey.getVersions().get("1").getCreationTime()); + assertTrue(mykey.getVersions().get("1") instanceof VaultTransitAsymmetricKeyVersion); + assertNotNull(((VaultTransitAsymmetricKeyVersion) mykey.getVersions().get("1")).getPublicKey()); + assertEquals(1, mykey.getLatestVersion()); + assertEquals(0, mykey.getMinAvailableVersion()); + assertEquals(1, mykey.getMinDecryptionVersion()); + assertEquals(0, mykey.getMinEncryptionVersion()); + + transitSecretEngine.updateKeyConfiguration(KEY_NAME, new KeyConfigRequestDetail().setDeletionAllowed(true)); + mykey = transitSecretEngine.readKey(KEY_NAME); + assertTrue(mykey.isDeletionAllowed()); + + transitSecretEngine.deleteKey(KEY_NAME); + assertNull(transitSecretEngine.readKey(KEY_NAME)); + } + + @Test + public void symmetricReadAESKey() { + + assertFalse(transitSecretEngine.listKeys().contains(KEY_NAME)); + transitSecretEngine.createKey(KEY_NAME, new KeyCreationRequestDetail().setType("aes256-gcm96")); + assertTrue(transitSecretEngine.listKeys().contains(KEY_NAME)); + + VaultTransitKeyDetail mykey = transitSecretEngine.readKey(KEY_NAME); + assertTrue(mykey instanceof VaultTransitSymmetricKeyDetail); + assertEquals(KEY_NAME, mykey.getName()); + assertFalse(mykey.isExportable()); + assertFalse(mykey.isDeletionAllowed()); + assertTrue(mykey.isSupportsDecryption()); + assertTrue(mykey.isSupportsEncryption()); + assertTrue(mykey.isSupportsDerivation()); + assertFalse(mykey.isSupportsSigning()); + assertEquals(mykey.getType(), "aes256-gcm96"); + assertEquals(1, mykey.getKeys().size()); + assertTrue(mykey.getKeys().containsKey("1")); + assertEquals(1, mykey.getVersions().size()); + assertTrue(mykey.getVersions().containsKey("1")); + assertNotNull(mykey.getVersions().get("1").getCreationTime()); + assertTrue(mykey.getVersions().get("1") instanceof VaultTransitSymmetricKeyVersion); + assertEquals(1, mykey.getLatestVersion()); + assertEquals(0, mykey.getMinAvailableVersion()); + assertEquals(1, mykey.getMinDecryptionVersion()); + assertEquals(0, mykey.getMinEncryptionVersion()); + + transitSecretEngine.updateKeyConfiguration(KEY_NAME, new KeyConfigRequestDetail().setDeletionAllowed(true)); + mykey = transitSecretEngine.readKey(KEY_NAME); + assertTrue(mykey.isDeletionAllowed()); + + transitSecretEngine.deleteKey(KEY_NAME); + assertNull(transitSecretEngine.readKey(KEY_NAME)); + } + } From 59bb18eb13ee0d4dc037cb00e4314ef86585f61e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 May 2021 15:54:10 +0000 Subject: [PATCH 0071/2077] Bump awssdk.version from 2.16.61 to 2.16.62 Bumps `awssdk.version` from 2.16.61 to 2.16.62. Updates `software.amazon.awssdk:bom` from 2.16.61 to 2.16.62 - [Release notes](https://github.com/aws/aws-sdk-java-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-java-v2/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java-v2/compare/2.16.61...2.16.62) Updates `apache-client` from 2.16.61 to 2.16.62 Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index f503180c5b658..2a71342dc1656 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -121,7 +121,7 @@ 2.3.2 1.4.197 42.2.20 - 2.7.2 + 2.7.3 8.0.25 7.2.2.jre8 21.1.0.0 @@ -150,7 +150,7 @@ 3.8.0 1.3.1 2.9.0 - 2.16.61 + 2.16.62 2.38.1 1.4.2 1.4.32 From b9f48b8ac9bb2fe091f93e5b83f832876364f941 Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Thu, 13 May 2021 19:02:58 +0100 Subject: [PATCH 0072/2077] Update OIDC/JWT docs how to check the errors in the logs and add info about Keycloak Frontend Url --- docs/src/main/asciidoc/security-jwt.adoc | 8 +++++++- .../security-openid-connect-client.adoc | 10 ++++++++++ ...rity-openid-connect-web-authentication.adoc | 18 ++++++++++++++++++ .../main/asciidoc/security-openid-connect.adoc | 16 ++++++++++++++++ 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/docs/src/main/asciidoc/security-jwt.adoc b/docs/src/main/asciidoc/security-jwt.adoc index b8793cfde9b88..82ec48594eb8e 100644 --- a/docs/src/main/asciidoc/security-jwt.adoc +++ b/docs/src/main/asciidoc/security-jwt.adoc @@ -765,7 +765,13 @@ See <> and learn how == How to check the errors in the logs == -Set `quarkus.log.category."io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator".level=TRACE` and `quarkus.log.category."io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator".min-level=TRACE` to see more details about the token verification or decryption errors. +Please enable `io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator` `TRACE` level logging to see more details about the token verification or decryption errors: + +[source, properties] +---- +quarkus.log.category."io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator".level=TRACE +quarkus.log.category."io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator".min-level=TRACE +---- == Proactive Authentication diff --git a/docs/src/main/asciidoc/security-openid-connect-client.adoc b/docs/src/main/asciidoc/security-openid-connect-client.adoc index 08c2f8897cade..e315a2e5da1b0 100644 --- a/docs/src/main/asciidoc/security-openid-connect-client.adoc +++ b/docs/src/main/asciidoc/security-openid-connect-client.adoc @@ -515,6 +515,16 @@ and finally write the test code. Given the Wiremock-based resource above, the fi If you work with Keycloak then you can use the same approach as described in the link:security-openid-connect#integration-testing-keycloak[OpenId Connect Bearer Token Integration testing] `Keycloak` section. +== How to check the errors in the logs == + +Please enable `io.quarkus.oidc.client.runtime.OidcClientImpl` `TRACE` level logging to see more details about the token acquisition and refresh errors: + +[source, properties] +---- +quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientImpl".level=TRACE +quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientImpl".min-level=TRACE +---- + == Token endpoint configuration By default the token endpoint address is discovered by adding a `/.well-known/openid-configuration` path to the configured `quarkus.oidc-client.auth-server-url`. diff --git a/docs/src/main/asciidoc/security-openid-connect-web-authentication.adoc b/docs/src/main/asciidoc/security-openid-connect-web-authentication.adoc index 3c661fc8b22b8..1925fe317b8e0 100644 --- a/docs/src/main/asciidoc/security-openid-connect-web-authentication.adoc +++ b/docs/src/main/asciidoc/security-openid-connect-web-authentication.adoc @@ -741,6 +741,24 @@ Default realm name is `quarkus` and client id - `quarkus-web-app` - set `keycloa Please see link:security-openid-connect#integration-testing-security-annotation[Use TestingSecurity with injected JsonWebToken] section for more information about using `@TestSecurity` and `@OidcSecurity` annotations for testing the `web-app` application endpoint code which depends on the injected ID and access `JsonWebToken` as well as `UserInfo` and `OidcConfigurationMetadata`. +== How to check the errors in the logs == + +Please enable `io.quarkus.oidc.runtime.OidcProvider` `TRACE` level logging to see more details about the token verification errors: + +[source, properties] +---- +quarkus.log.category."io.quarkus.oidc.runtime.OidcProvider".level=TRACE +quarkus.log.category."io.quarkus.oidc.runtime.OidcProvider".min-level=TRACE +---- + +== External and Internal Access to OpenId Connect Provider + +Note that the OpenId Connect Provider externally accessible authorization, logout and other endpoints may have different HTTP(S) URLs compared to the URLs auto-discovered or configured relative to `quarkus.oidc.auth-server-url` internal URL. +In such cases an issuer verification failure may be reported by the endpoint and redirects to the externally accessible Connect Provider endpoints may fail. + +In such cases, if you work with Keycloak then please start it with a `KEYCLOAK_FRONTEND_URL` system property set to the externally accessible base URL. +If you work with other Openid Connect providers then please check your provider's documentation. + == Configuration Reference include::{generated-dir}/config/quarkus-oidc.adoc[opts=optional] diff --git a/docs/src/main/asciidoc/security-openid-connect.adoc b/docs/src/main/asciidoc/security-openid-connect.adoc index 2820ff51a2663..f891aa99637df 100644 --- a/docs/src/main/asciidoc/security-openid-connect.adoc +++ b/docs/src/main/asciidoc/security-openid-connect.adoc @@ -769,6 +769,22 @@ Note that `@TestSecurity` annotation must always be used and its `user` property `@OidcSecurity` annotation is optional and can be used to set the additional token claims, as well as `UserInfo` and `OidcConfigurationMetadata` properties. Additionally, if `quarkus.oidc.token.issuer` property is configured then it will be used as an `OidcConfigurationMetadata` `issuer` property value. +== How to check the errors in the logs == + +Please enable `io.quarkus.oidc.runtime.OidcProvider` `TRACE` level logging to see more details about the token verification errors: + +[source, properties] +---- +quarkus.log.category."io.quarkus.oidc.runtime.OidcProvider".level=TRACE +quarkus.log.category."io.quarkus.oidc.runtime.OidcProvider".min-level=TRACE +---- + +== External and Internal Access to OpenId Connect Provider + +Note that the OpenId Connect Provider externally accessible token and other endpoints may have different HTTP(S) URLs compared to the URLs auto-discovered or configured relative to `quarkus.oidc.auth-server-url` internal URL. For example, if your SPA acquires a token from an external token endpoint address and sends it to Quarkus as a Bearer token then an issuer verification failure may be reported by the endpoint. + +In such cases, if you work with Keycloak then please start it with a `KEYCLOAK_FRONTEND_URL` system property set to the externally accessible base URL. +If you work with other Openid Connect providers then please check your provider's documentation. == References From d853df0edeb229cda51a2141f2ef1e902b417447 Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Wed, 12 May 2021 14:23:05 +0100 Subject: [PATCH 0073/2077] Keycloak Authorization must block access to the public resource if a matching enforcing policy exists --- .../security-keycloak-authorization.adoc | 31 +++++++++++++++++-- .../KeycloakPolicyEnforcerAuthorizer.java | 12 +++++-- .../quarkus/it/keycloak/PublicResource.java | 15 ++++++++- .../src/main/resources/application.properties | 6 ++++ .../it/keycloak/PolicyEnforcerTest.java | 24 ++++++++++++++ 5 files changed, 82 insertions(+), 6 deletions(-) diff --git a/docs/src/main/asciidoc/security-keycloak-authorization.adoc b/docs/src/main/asciidoc/security-keycloak-authorization.adoc index de4e76ec9ede2..ec28dce507fb9 100644 --- a/docs/src/main/asciidoc/security-keycloak-authorization.adoc +++ b/docs/src/main/asciidoc/security-keycloak-authorization.adoc @@ -15,7 +15,7 @@ In other words, instead of explicitly enforcing access based on some specific ac By externalizing authorization from your application, you are allowed to protect your applications using different access control mechanisms as well as avoid re-deploying your application every time your security requirements change, where Keycloak will be acting as a centralized authorization service from where your protected resources and their associated permissions are managed. -See the link:security-openid-connect[Using OpenID Connect to Protect Service Applications] guide for more information about `Bearer Token` authentication mechanism. +See the link:security-openid-connect[Using OpenID Connect to Protect Service Applications] guide for more information about `Bearer Token` authentication mechanism. It is important to realize that it is the `Bearer Token` authentication mechanism which does the authentication and creates a security identity - while the `quarkus-keycloak-authorization` extension is responsible for applying a Keycloak Authorization Policy to this identity based on the current request path and other policy settings. If you are already familiar with Keycloak, you’ll notice that the extension is basically another adapter implementation but specific for Quarkus applications. Otherwise, you can find more information in the Keycloak https://www.keycloak.org/docs/latest/authorization_services/index.html#_enforcer_overview[documentation]. @@ -339,6 +339,7 @@ specific operations like managing resources and obtaining permissions directly f [source,java] ---- +public class ProtectedResource { @Inject AuthzClient authzClient; } @@ -357,11 +358,35 @@ quarkus.keycloak.policy-enforcer.lazy-load-paths=false Note that, depending on how many resources you have in Keycloak the time taken to fetch them may impact your application startup time. -== More About Configuring Protected Resources +== More About Configuring Protected Resources In the default configuration, Keycloak is responsible for managing the roles and deciding who can access which routes. -To configure the protected routes using the `@RolesAllowed` annotation or the `application.properties` file, check the link:security-openid-connect[Using OpenID Connect Adapter to Protect JAX-RS Applications] guide. For more details, check the link:security[Security guide]. +To configure the protected routes using the `@RolesAllowed` annotation or the `application.properties` file, check the link:security-openid-connect[Using OpenID Connect Adapter to Protect JAX-RS Applications] and link:security-authorization[Security Authorization] guides. For more details, check the link:security[Security guide]. + +== Access to Public Resources + +If you'd like to access a public resource without `quarkus-keycloak-authorization` trying to apply its policies to it then you need to create a `permit` HTTP Policy configuration in `application.properties` as documented in the link:security-authorization[Security Authorization] guide. + +Disabling a policy check using a Keycloak Authorization Policy such as: + +[source,properties] +---- +quarkus.keycloak.policy-enforcer.paths.1.path=/api/public +quarkus.keycloak.policy-enforcer.paths.1.enforcement-mode=DISABLED +---- + +is no longer required. + +If you'd like to block an access to the public resource to anonymous users then you can create an enforcing Keycloak Authorization Policy: + +[source,properties] +---- +quarkus.keycloak.policy-enforcer.paths.1.path=/api/public-enforcing +quarkus.keycloak.policy-enforcer.paths.1.enforcement-mode=ENFORCING +---- + +Note only the default tenant configuration applies when controlling an anonymous access to the public resource is required. == Multi-Tenancy diff --git a/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerAuthorizer.java b/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerAuthorizer.java index ad347b1bfd287..2f7f51c25ded5 100644 --- a/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerAuthorizer.java +++ b/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerAuthorizer.java @@ -14,6 +14,8 @@ import org.keycloak.AuthorizationContext; import org.keycloak.adapters.authorization.KeycloakAdapterPolicyEnforcer; import org.keycloak.authorization.client.AuthzClient; +import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.EnforcementMode; +import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig; import io.quarkus.arc.Arc; import io.quarkus.oidc.AccessTokenCredential; @@ -41,11 +43,17 @@ public Uni checkPermission(RoutingContext request, Uni Date: Thu, 13 May 2021 18:49:21 +0000 Subject: [PATCH 0074/2077] Bump gizmo from 1.0.7.Final to 1.0.8.Final Bumps [gizmo](https://github.com/quarkusio/gizmo) from 1.0.7.Final to 1.0.8.Final. - [Release notes](https://github.com/quarkusio/gizmo/releases) - [Commits](https://github.com/quarkusio/gizmo/compare/1.0.7.Final...1.0.8.Final) Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- independent-projects/arc/pom.xml | 2 +- independent-projects/qute/pom.xml | 2 +- independent-projects/resteasy-reactive/pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index a2673330f00f0..5b576cb796c09 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -87,7 +87,7 @@ 2.1.0 21.1.0 - 1.0.7.Final + 1.0.8.Final 2.12.3 1.0.0.Final 3.12.0 diff --git a/independent-projects/arc/pom.xml b/independent-projects/arc/pom.xml index 4d3ec1a287571..bc7f79c106918 100644 --- a/independent-projects/arc/pom.xml +++ b/independent-projects/arc/pom.xml @@ -44,7 +44,7 @@ 3.19.0 3.4.1.Final 1.3.5 - 1.0.7.Final + 1.0.8.Final 2.2.3 3.0.0-M5 diff --git a/independent-projects/qute/pom.xml b/independent-projects/qute/pom.xml index 67b098de50670..dcb3ae03448b0 100644 --- a/independent-projects/qute/pom.xml +++ b/independent-projects/qute/pom.xml @@ -37,7 +37,7 @@ 11 11 5.7.1 - 1.0.7.Final + 1.0.8.Final 3.4.1.Final 3.0.0-M5 1.6.8 diff --git a/independent-projects/resteasy-reactive/pom.xml b/independent-projects/resteasy-reactive/pom.xml index a53b90e47a9af..e99b047f44088 100644 --- a/independent-projects/resteasy-reactive/pom.xml +++ b/independent-projects/resteasy-reactive/pom.xml @@ -43,7 +43,7 @@ 3.19.0 3.4.1.Final 1.3.5 - 1.0.7.Final + 1.0.8.Final 2.2.3 3.0.0-M5 From 482814d59f562cdd700dd800b35cab8c389a1785 Mon Sep 17 00:00:00 2001 From: Daniel Schmidt Date: Thu, 13 May 2021 20:44:02 +0200 Subject: [PATCH 0075/2077] Fix mvn parameter for dockerbuild on windows in aws-lambda guide --- docs/src/main/asciidoc/amazon-lambda.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/main/asciidoc/amazon-lambda.adoc b/docs/src/main/asciidoc/amazon-lambda.adoc index aad26db36ed2e..fe472def799f7 100644 --- a/docs/src/main/asciidoc/amazon-lambda.adoc +++ b/docs/src/main/asciidoc/amazon-lambda.adoc @@ -258,11 +258,11 @@ or, if using Gradle: NOTE: If you are building on a non-Linux system, you will need to also pass in a property instructing quarkus to use a docker build as Amazon Lambda requires linux binaries. You can do this by passing this property to your Maven build: -`-Dnative-image.docker-build=true`, or for Gradle: `--docker-build=true`. This requires you to have docker installed locally, however. +`-Dquarkus.native.container-build=true`, or for Gradle: `--docker-build=true`. This requires you to have docker installed locally, however. [source,bash,subs=attributes+] ---- -./mvnw clean install -Pnative -Dnative-image.docker-build=true +./mvnw clean install -Pnative -Dquarkus.native.container-build=true ---- or, if using Gradle: From 8a70ee210e1f466de19006fd938feaa44c90b687 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 May 2021 21:10:10 +0000 Subject: [PATCH 0076/2077] Bump mockito-core from 3.9.0 to 3.10.0 Bumps [mockito-core](https://github.com/mockito/mockito) from 3.9.0 to 3.10.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.9.0...v3.10.0) Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- independent-projects/tools/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 2a71342dc1656..d180517995364 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -183,7 +183,7 @@ 5.2.Final 2.1.SP1 2.40.0 - 3.9.0 + 3.10.0 5.3.1 4.8 1.1.4.Final diff --git a/independent-projects/tools/pom.xml b/independent-projects/tools/pom.xml index e792de79ac268..9f7c397862d9e 100644 --- a/independent-projects/tools/pom.xml +++ b/independent-projects/tools/pom.xml @@ -48,7 +48,7 @@ 1.20 3.4.1.Final 3.8.1 - 3.9.0 + 3.10.0 3.0.0-M5 1.6.8 999-SNAPSHOT From 703a6560986255beac64b4e3a3060fc78d3b98af Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Fri, 14 May 2021 10:15:05 +1000 Subject: [PATCH 0077/2077] Resteasy hangs on null header Also fix Resteasy Reactive which would not hang but would fail with an NPE. Fixes #17168 --- .../resteasy/test/NullHeaderTestCase.java | 55 +++++++++++++++++++ .../runtime/standalone/VertxHttpResponse.java | 12 ++-- .../test/response/NullHeaderTestCase.java | 55 +++++++++++++++++++ .../server/core/ServerSerialisers.java | 4 +- 4 files changed, 121 insertions(+), 5 deletions(-) create mode 100644 extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/NullHeaderTestCase.java create mode 100644 extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/response/NullHeaderTestCase.java diff --git a/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/NullHeaderTestCase.java b/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/NullHeaderTestCase.java new file mode 100644 index 0000000000000..460af28534fc0 --- /dev/null +++ b/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/NullHeaderTestCase.java @@ -0,0 +1,55 @@ +package io.quarkus.resteasy.test; + +import static io.restassured.RestAssured.when; + +import java.io.IOException; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerResponseContext; +import javax.ws.rs.container.ContainerResponseFilter; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.Provider; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +//https://github.com/quarkusio/quarkus/issues/17168 +class NullHeaderTestCase { + + @RegisterExtension + static QuarkusUnitTest runner = new QuarkusUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addClasses(NullFilter.class, NullResource.class)); + + @Test + void nullHeaderTest() { + when() + .get("/null") + .then().statusCode(200) + .header("nullHeader", ""); + } + + @Provider + public static class NullFilter implements ContainerResponseFilter { + + @Override + public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) + throws IOException { + responseContext.getHeaders().add("nullHeader", null); + } + } + + @Path("/null") + public static class NullResource { + @GET + public Response ok() { + return Response.ok().build(); + } + } +} diff --git a/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/VertxHttpResponse.java b/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/VertxHttpResponse.java index 006d7a628611b..09a2021860e4b 100644 --- a/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/VertxHttpResponse.java +++ b/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/VertxHttpResponse.java @@ -122,11 +122,15 @@ public static void transformHeaders(VertxHttpResponse vertxResponse, HttpServerR for (Map.Entry> entry : vertxResponse.getOutputHeaders().entrySet()) { String key = entry.getKey(); for (Object value : entry.getValue()) { - RuntimeDelegate.HeaderDelegate delegate = factory.getHeaderDelegate(value.getClass()); - if (delegate != null) { - response.headers().add(key, delegate.toString(value)); + if (value == null) { + response.headers().add(key, ""); } else { - response.headers().add(key, value.toString()); + RuntimeDelegate.HeaderDelegate delegate = factory.getHeaderDelegate(value.getClass()); + if (delegate != null) { + response.headers().add(key, delegate.toString(value)); + } else { + response.headers().add(key, value.toString()); + } } } } diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/response/NullHeaderTestCase.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/response/NullHeaderTestCase.java new file mode 100644 index 0000000000000..67200144cbe74 --- /dev/null +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/response/NullHeaderTestCase.java @@ -0,0 +1,55 @@ +package io.quarkus.resteasy.reactive.server.test.response; + +import static io.restassured.RestAssured.when; + +import java.io.IOException; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerResponseContext; +import javax.ws.rs.container.ContainerResponseFilter; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.Provider; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +//https://github.com/quarkusio/quarkus/issues/17168 +class NullHeaderTestCase { + + @RegisterExtension + static QuarkusUnitTest runner = new QuarkusUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addClasses(NullFilter.class, NullResource.class)); + + @Test + void nullHeaderTest() { + when() + .get("/null") + .then().statusCode(200) + .header("nullHeader", ""); + } + + @Provider + public static class NullFilter implements ContainerResponseFilter { + + @Override + public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) + throws IOException { + responseContext.getHeaders().add("nullHeader", null); + } + } + + @Path("/null") + public static class NullResource { + @GET + public Response ok() { + return Response.ok().build(); + } + } +} diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ServerSerialisers.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ServerSerialisers.java index 8ea1f19df6089..82c461b48ce53 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ServerSerialisers.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ServerSerialisers.java @@ -492,7 +492,9 @@ public static void encodeResponseHeaders(ResteasyReactiveRequestContext requestC for (Map.Entry> entry : headers.entrySet()) { if (entry.getValue().size() == 1) { Object o = entry.getValue().get(0); - if (o instanceof CharSequence) { + if (o == null) { + vertxResponse.setResponseHeader(entry.getKey(), ""); + } else if (o instanceof CharSequence) { vertxResponse.setResponseHeader(entry.getKey(), (CharSequence) o); } else { vertxResponse.setResponseHeader(entry.getKey(), (CharSequence) HeaderUtil.headerToString(o)); From 5faee10260927bf1daba94505b3529221fd175a8 Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Tue, 4 May 2021 15:04:53 +1000 Subject: [PATCH 0078/2077] Add quarkus:test goal This enables continuous testing without starting the application in dev mode. --- .../deployment/dev/IsolatedTestModeMain.java | 155 ++++++++++++++++++ .../deployment/dev/testing/TestHandler.java | 13 ++ .../dev/testing/TestSetupBuildItem.java | 11 ++ .../dev/testing/TestTracingProcessor.java | 1 + .../java/io/quarkus/dev/spi/DevModeType.java | 3 +- .../java/io/quarkus/gradle/QuarkusPlugin.java | 8 +- .../io/quarkus/gradle/tasks/QuarkusTest.java | 22 +++ .../main/java/io/quarkus/maven/TestMojo.java | 26 +++ .../src/main/asciidoc/continuous-testing.adoc | 9 +- 9 files changed, 245 insertions(+), 3 deletions(-) create mode 100644 core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedTestModeMain.java create mode 100644 core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestHandler.java create mode 100644 core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestSetupBuildItem.java create mode 100644 devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusTest.java create mode 100644 devtools/maven/src/main/java/io/quarkus/maven/TestMojo.java diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedTestModeMain.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedTestModeMain.java new file mode 100644 index 0000000000000..b57517a484cd9 --- /dev/null +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedTestModeMain.java @@ -0,0 +1,155 @@ +package io.quarkus.deployment.dev; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; + +import io.quarkus.bootstrap.app.AugmentAction; +import io.quarkus.bootstrap.app.CuratedApplication; +import io.quarkus.bootstrap.runner.Timing; +import io.quarkus.deployment.dev.testing.TestHandler; +import io.quarkus.deployment.dev.testing.TestSetupBuildItem; +import io.quarkus.deployment.dev.testing.TestSupport; +import io.quarkus.deployment.logging.LoggingSetupBuildItem; +import io.quarkus.deployment.steps.ClassTransformingBuildStep; +import io.quarkus.dev.spi.DevModeType; +import io.quarkus.dev.spi.HotReplacementSetup; +import io.quarkus.runner.bootstrap.AugmentActionImpl; +import io.quarkus.runtime.logging.LoggingSetupRecorder; + +/** + * The main entry point of quarkus:test + */ +public class IsolatedTestModeMain extends IsolatedDevModeMain { + + private volatile DevModeContext context; + + private final List hotReplacementSetups = new ArrayList<>(); + static volatile Throwable deploymentProblem; + private static volatile CuratedApplication curatedApplication; + private static volatile AugmentAction augmentAction; + + private RuntimeUpdatesProcessor setupRuntimeCompilation(DevModeContext context, Path applicationRoot) + throws Exception { + if (!context.getAllModules().isEmpty()) { + ServiceLoader serviceLoader = ServiceLoader.load(CompilationProvider.class); + List compilationProviders = new ArrayList<>(); + for (CompilationProvider provider : serviceLoader) { + compilationProviders.add(provider); + context.getAllModules().forEach(moduleInfo -> moduleInfo.addSourcePaths(provider.handledSourcePaths())); + } + QuarkusCompiler compiler; + try { + compiler = new QuarkusCompiler(curatedApplication, compilationProviders, context); + } catch (Exception e) { + throw new RuntimeException("Failed to create compiler", e); + } + TestSupport testSupport = new TestSupport(curatedApplication, compilationProviders, context); + RuntimeUpdatesProcessor processor = new RuntimeUpdatesProcessor(applicationRoot, context, compiler, + DevModeType.TEST_ONLY, this::regenerateApplication, + new BiConsumer() { + @Override + public void accept(DevModeContext.ModuleInfo moduleInfo, String s) { + } + }, new BiFunction() { + @Override + public byte[] apply(String s, byte[] bytes) { + return ClassTransformingBuildStep.transform(s, bytes); + } + }, testSupport); + + for (HotReplacementSetup service : ServiceLoader.load(HotReplacementSetup.class, + curatedApplication.getBaseRuntimeClassLoader())) { + hotReplacementSetups.add(service); + service.setupHotDeployment(processor); + processor.addHotReplacementSetup(service); + } + return processor; + } + return null; + } + + void regenerateApplication(Set ignore, ClassScanResult ignore2) { + } + + public void close() { + try { + try { + RuntimeUpdatesProcessor.INSTANCE.close(); + } catch (IOException e) { + e.printStackTrace(); + } + for (HotReplacementSetup i : hotReplacementSetups) { + i.close(); + } + } finally { + curatedApplication.close(); + } + + } + + //the main entry point, but loaded inside the augmentation class loader + @Override + public void accept(CuratedApplication o, Map params) { + Timing.staticInitStarted(o.getBaseRuntimeClassLoader(), false); + try { + curatedApplication = o; + Object potentialContext = params.get(DevModeContext.class.getName()); + if (potentialContext instanceof DevModeContext) { + context = (DevModeContext) potentialContext; + } else { + //this was from the external class loader + //we need to copy it into this one + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ObjectOutputStream oo = new ObjectOutputStream(out); + oo.writeObject(potentialContext); + context = (DevModeContext) new ObjectInputStream(new ByteArrayInputStream(out.toByteArray())).readObject(); + } + + augmentAction = new AugmentActionImpl(curatedApplication); + RuntimeUpdatesProcessor.INSTANCE = setupRuntimeCompilation(context, (Path) params.get(APP_ROOT)); + + if (RuntimeUpdatesProcessor.INSTANCE != null) { + RuntimeUpdatesProcessor.INSTANCE.checkForFileChange(); + RuntimeUpdatesProcessor.INSTANCE.checkForChangedClasses(true); + } + try { + augmentAction.performCustomBuild(TestHandler.class.getName(), null, TestSetupBuildItem.class.getName(), + LoggingSetupBuildItem.class.getName()); + } catch (Throwable t) { + //logging may not have been started, this is more reliable + System.err.println("Failed to start quarkus test mode"); + t.printStackTrace(); + System.exit(1); + } + //we don't actually start the app + //so logging would not be enabled + LoggingSetupRecorder.handleFailedStart(); + + Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { + @Override + public void run() { + synchronized (DevModeMain.class) { + try { + close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + }, "Quarkus Shutdown Thread")); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestHandler.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestHandler.java new file mode 100644 index 0000000000000..84ca23784f7ec --- /dev/null +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestHandler.java @@ -0,0 +1,13 @@ +package io.quarkus.deployment.dev.testing; + +import java.util.function.BiConsumer; + +import io.quarkus.builder.BuildResult; + +public class TestHandler implements BiConsumer { + @Override + public void accept(Object o, BuildResult buildResult) { + TestSupport.instance().get().start(); + + } +} diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestSetupBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestSetupBuildItem.java new file mode 100644 index 0000000000000..da2ff9fa4c851 --- /dev/null +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestSetupBuildItem.java @@ -0,0 +1,11 @@ +package io.quarkus.deployment.dev.testing; + +import io.quarkus.builder.item.MultiBuildItem; + +/** + * Virtual build item that is used to signify that a step must be run to setup + * continuous testing + */ +public final class TestSetupBuildItem extends MultiBuildItem { + +} diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestTracingProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestTracingProcessor.java index 9755006be371f..a267151241fa9 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestTracingProcessor.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestTracingProcessor.java @@ -63,6 +63,7 @@ void setupConsole(TestConfig config, BuildProducer testLi @BuildStep(onlyIfNot = IsNormal.class) @Produce(LogHandlerBuildItem.class) + @Produce(TestSetupBuildItem.class) ServiceStartBuildItem startTesting(TestConfig config, LiveReloadBuildItem liveReloadBuildItem, LaunchModeBuildItem launchModeBuildItem, List testListenerBuildItems) { if (!TestSupport.instance().isPresent() || config.continuousTesting == TestConfig.Mode.DISABLED diff --git a/core/devmode-spi/src/main/java/io/quarkus/dev/spi/DevModeType.java b/core/devmode-spi/src/main/java/io/quarkus/dev/spi/DevModeType.java index 03229cdffed79..f1c36cf428dfd 100644 --- a/core/devmode-spi/src/main/java/io/quarkus/dev/spi/DevModeType.java +++ b/core/devmode-spi/src/main/java/io/quarkus/dev/spi/DevModeType.java @@ -3,5 +3,6 @@ public enum DevModeType { LOCAL, REMOTE_LOCAL_SIDE, - REMOTE_SERVER_SIDE + REMOTE_SERVER_SIDE, + TEST_ONLY } diff --git a/devtools/gradle/src/main/java/io/quarkus/gradle/QuarkusPlugin.java b/devtools/gradle/src/main/java/io/quarkus/gradle/QuarkusPlugin.java index f61804ee4a884..11f135a3d1c2d 100644 --- a/devtools/gradle/src/main/java/io/quarkus/gradle/QuarkusPlugin.java +++ b/devtools/gradle/src/main/java/io/quarkus/gradle/QuarkusPlugin.java @@ -42,6 +42,7 @@ import io.quarkus.gradle.tasks.QuarkusListPlatforms; import io.quarkus.gradle.tasks.QuarkusRemoteDev; import io.quarkus.gradle.tasks.QuarkusRemoveExtension; +import io.quarkus.gradle.tasks.QuarkusTest; import io.quarkus.gradle.tasks.QuarkusTestConfig; import io.quarkus.gradle.tasks.QuarkusTestNative; @@ -61,6 +62,7 @@ public class QuarkusPlugin implements Plugin { public static final String GENERATE_CONFIG_TASK_NAME = "generateConfig"; public static final String QUARKUS_DEV_TASK_NAME = "quarkusDev"; public static final String QUARKUS_REMOTE_DEV_TASK_NAME = "quarkusRemoteDev"; + public static final String QUARKUS_TEST_TASK_NAME = "quarkusTest"; public static final String DEV_MODE_CONFIGURATION_NAME = "quarkusDev"; public static final String ANNOTATION_PROCESSOR_CONFIGURATION_NAME = "quarkusAnnotationProcessor"; @@ -110,6 +112,7 @@ private void registerTasks(Project project, QuarkusPluginExtension quarkusExt) { quarkusBuild.dependsOn(quarkusGenerateCode); Task quarkusDev = tasks.create(QUARKUS_DEV_TASK_NAME, QuarkusDev.class); Task quarkusRemoteDev = tasks.create(QUARKUS_REMOTE_DEV_TASK_NAME, QuarkusRemoteDev.class); + Task quarkusTest = tasks.create(QUARKUS_TEST_TASK_NAME, QuarkusTest.class); tasks.create(QUARKUS_TEST_CONFIG_TASK_NAME, QuarkusTestConfig.class); Task buildNative = tasks.create(BUILD_NATIVE_TASK_NAME, DefaultTask.class); @@ -161,8 +164,11 @@ public void execute(Task test) { Task resourcesTask = tasks.getByName(JavaPlugin.PROCESS_RESOURCES_TASK_NAME); Task testClassesTask = tasks.getByName(JavaPlugin.TEST_CLASSES_TASK_NAME); Task testResourcesTask = tasks.getByName(JavaPlugin.PROCESS_TEST_RESOURCES_TASK_NAME); - quarkusDev.dependsOn(classesTask, resourcesTask, testClassesTask, testResourcesTask, quarkusGenerateCode); + quarkusDev.dependsOn(classesTask, resourcesTask, testClassesTask, testResourcesTask, quarkusGenerateCode, + quarkusGenerateCodeTests); quarkusRemoteDev.dependsOn(classesTask, resourcesTask); + quarkusTest.dependsOn(classesTask, resourcesTask, testClassesTask, testResourcesTask, quarkusGenerateCode, + quarkusGenerateCodeTests); quarkusBuild.dependsOn(classesTask, resourcesTask, tasks.getByName(JavaPlugin.JAR_TASK_NAME)); SourceSetContainer sourceSets = project.getConvention().getPlugin(JavaPluginConvention.class) diff --git a/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusTest.java b/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusTest.java new file mode 100644 index 0000000000000..228487ba006b2 --- /dev/null +++ b/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusTest.java @@ -0,0 +1,22 @@ +package io.quarkus.gradle.tasks; + +import java.util.function.Consumer; + +import io.quarkus.deployment.dev.DevModeContext; +import io.quarkus.deployment.dev.IsolatedTestModeMain; + +public class QuarkusTest extends QuarkusDev { + + public QuarkusTest() { + super("Continuous testing mode: enables continuous testing without starting dev mode"); + } + + protected void modifyDevModeContext(GradleDevModeLauncher.Builder builder) { + builder.entryPointCustomizer(new Consumer() { + @Override + public void accept(DevModeContext devModeContext) { + devModeContext.setAlternateEntryPoint(IsolatedTestModeMain.class.getName()); + } + }); + } +} diff --git a/devtools/maven/src/main/java/io/quarkus/maven/TestMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/TestMojo.java new file mode 100644 index 0000000000000..5518800682c88 --- /dev/null +++ b/devtools/maven/src/main/java/io/quarkus/maven/TestMojo.java @@ -0,0 +1,26 @@ +package io.quarkus.maven; + +import java.util.function.Consumer; + +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.ResolutionScope; + +import io.quarkus.deployment.dev.DevModeContext; +import io.quarkus.deployment.dev.IsolatedTestModeMain; + +/** + * The test mojo, that starts continuous testing outside of dev mode + */ +@Mojo(name = "test", defaultPhase = LifecyclePhase.PREPARE_PACKAGE, requiresDependencyResolution = ResolutionScope.TEST) +public class TestMojo extends DevMojo { + @Override + protected void modifyDevModeContext(MavenDevModeLauncher.Builder builder) { + builder.entryPointCustomizer(new Consumer() { + @Override + public void accept(DevModeContext devModeContext) { + devModeContext.setAlternateEntryPoint(IsolatedTestModeMain.class.getName()); + } + }); + } +} diff --git a/docs/src/main/asciidoc/continuous-testing.adoc b/docs/src/main/asciidoc/continuous-testing.adoc index 5c2cc3551d915..f12ebcdb75b0a 100644 --- a/docs/src/main/asciidoc/continuous-testing.adoc +++ b/docs/src/main/asciidoc/continuous-testing.adoc @@ -141,8 +141,15 @@ This is not directly related to testing, but allows you to turn live reload on a This will force a scan for changed file, and will perform a live reload if anything has changed. This will still work even if live reload is disabled. +== Continuous Testing Without Dev Mode -=== Configuring Continuous Testing +It is possible to run continous testing without starting dev mode. This can be useful if dev mode will interfere with +your tests (e.g. running wiremock on the same port), or if you only want to develop using tests. To start continuous testing +mode run `mvn quarkus:test`. + +NOTE: The Dev UI is not available when running in continuous testing mode, as this is provided by dev mode. + +== Configuring Continuous Testing Continuous testing supports multiple configuration options that can be used to limit the tests that are run, and to control the output. The configuration properties are shown below: From d5536461fc7c53c85be9c837607b9992ca550717 Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Fri, 14 May 2021 14:30:38 +1000 Subject: [PATCH 0079/2077] Rename quarkus-extension.yaml This avoids problems with the IDE overwriting changes made by the bootstrap plugin. --- ...sion.yaml => quarkus-extension.yaml.template} | 0 docs/src/main/asciidoc/writing-extensions.adoc | 3 +++ ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 .../orm/HibernateHotReloadTestCase.java | 1 + ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 .../quarkus/maven/ExtensionDescriptorMojo.java | 16 ++++++++++++++-- ...sion.yaml => quarkus-extension.yaml.template} | 0 ...sion.yaml => quarkus-extension.yaml.template} | 0 200 files changed, 18 insertions(+), 2 deletions(-) rename core/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/agroal/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/amazon-alexa/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/amazon-lambda-http/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/amazon-lambda-rest/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/amazon-lambda-xray/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/amazon-lambda/common-runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/amazon-lambda/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/amazon-services/common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/amazon-services/dynamodb/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/amazon-services/iam/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/amazon-services/kms/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/amazon-services/s3/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/amazon-services/ses/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/amazon-services/sns/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/amazon-services/sqs/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/amazon-services/ssm/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/apache-httpclient/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/arc/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/artemis-core/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/artemis-jms/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/avro/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/azure-functions-http/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/cache/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/caffeine/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/config-yaml/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/consul-config/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/container-image/container-image-docker/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/container-image/container-image-jib/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/container-image/container-image-openshift/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/container-image/container-image-s2i/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/container-image/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/datasource/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/elasticsearch-rest-client-common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/elasticsearch-rest-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/elasticsearch-rest-high-level-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/elytron-security-common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/elytron-security-jdbc/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/elytron-security-ldap/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/elytron-security-oauth2/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/elytron-security-properties-file/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/elytron-security/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/flyway/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/funqy/funqy-amazon-lambda/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/funqy/funqy-google-cloud-functions/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/funqy/funqy-http/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/funqy/funqy-knative-events/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/funqy/funqy-server-common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/google-cloud-functions-http/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/google-cloud-functions/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/grpc-common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/grpc/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/hibernate-envers/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/hibernate-orm/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/hibernate-reactive/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/hibernate-search-orm-elasticsearch/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/hibernate-validator/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/infinispan-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/jackson/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/jaeger/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/jaxb/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/jaxp/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/jdbc/jdbc-db2/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/jdbc/jdbc-derby/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/jdbc/jdbc-h2/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/jdbc/jdbc-mariadb/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/jdbc/jdbc-mssql/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/jdbc/jdbc-mysql/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/jdbc/jdbc-oracle/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/jdbc/jdbc-postgresql/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/jgit/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/jsch/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/jsonb/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/jsonp/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/kafka-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/kafka-streams/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/keycloak-admin-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/keycloak-authorization/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/kotlin/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/kubernetes-client/runtime-internal/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/kubernetes-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/kubernetes-config/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/kubernetes-service-binding/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/kubernetes/minikube/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/kubernetes/openshift/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/kubernetes/vanilla/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/liquibase/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/logging-gelf/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/logging-json/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/logging-sentry/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/mailer/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/micrometer-registry-prometheus/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/micrometer/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/mongodb-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/mutiny/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/narayana-jta/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/narayana-stm/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/neo4j/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/netty/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/oidc-client-filter/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/oidc-client-reactive-filter/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/oidc-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/oidc-common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/oidc-token-propagation/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/oidc/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/openshift-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/opentelemetry-exporter-jaeger/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/opentelemetry/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/panache/hibernate-orm-panache-common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/panache/hibernate-orm-panache-kotlin/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/panache/hibernate-orm-panache/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/panache/hibernate-orm-rest-data-panache/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/panache/hibernate-reactive-panache-common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/panache/hibernate-reactive-panache/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/panache/mongodb-panache-common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/panache/mongodb-panache-kotlin/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/panache/mongodb-panache/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/panache/mongodb-rest-data-panache/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/panache/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/picocli/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/quartz/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/qute/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/reactive-datasource/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/reactive-db2-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/reactive-messaging-http/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/reactive-mysql-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/reactive-pg-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/reactive-streams-operators/mutiny-reactive-streams-operators/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/reactive-streams-operators/smallrye-reactive-streams-operators/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/reactive-streams-operators/smallrye-reactive-type-converters/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/redis-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-classic/rest-client-jackson/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-classic/rest-client-jaxb/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-classic/rest-client-jsonb/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-classic/rest-client-mutiny/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-classic/rest-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-classic/resteasy-common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-classic/resteasy-jackson/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-classic/resteasy-jaxb/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-classic/resteasy-jsonb/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-classic/resteasy-multipart/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-classic/resteasy-mutiny-common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-classic/resteasy-mutiny/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-classic/resteasy-qute/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-classic/resteasy-server-common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-classic/resteasy/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-reactive/jaxrs-client-reactive/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson-common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-reactive/quarkus-resteasy-reactive-links/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-reactive/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-reactive/quarkus-resteasy-reactive-qute/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-reactive/quarkus-resteasy-reactive-servlet/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-reactive/rest-client-reactive-jackson/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/scala/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/scheduler/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/security-jpa/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/security/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/smallrye-context-propagation/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/smallrye-fault-tolerance/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/smallrye-graphql/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/smallrye-health/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/smallrye-jwt-build/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/smallrye-jwt/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/smallrye-metrics/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/smallrye-openapi/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/smallrye-opentracing/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/smallrye-reactive-messaging-amqp/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/smallrye-reactive-messaging-kafka/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/smallrye-reactive-messaging-mqtt/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/smallrye-reactive-messaging/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/spring-boot-properties/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/spring-cache/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/spring-cloud-config-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/spring-data-jpa/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/spring-data-rest/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/spring-di/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/spring-scheduled/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/spring-security/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/spring-web/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/swagger-ui/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/tika/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/undertow/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/vault/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/vertx-core/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/vertx-graphql/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/vertx-http/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/vertx-web/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/vertx/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/webjars-locator/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename extensions/websockets/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename integration-tests/gradle/src/test/resources/test-resources-in-build-steps/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) rename test-framework/jacoco/runtime/src/main/resources/META-INF/{quarkus-extension.yaml => quarkus-extension.yaml.template} (100%) diff --git a/core/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/core/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from core/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to core/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/docs/src/main/asciidoc/writing-extensions.adoc b/docs/src/main/asciidoc/writing-extensions.adoc index 5605484192038..30e9c920fc6ea 100644 --- a/docs/src/main/asciidoc/writing-extensions.adoc +++ b/docs/src/main/asciidoc/writing-extensions.adoc @@ -535,6 +535,9 @@ TIP: The `name` parameter of the mojo is optional. If you do not specify it on the command line, the plugin will derive it from `extensionId` by replacing dashes with spaces and uppercasing each token. So you may consider omitting explicit `name` in some cases. +NOTE: You can also name your file `quarkus-extension.yaml.template` and the plugin will rename it for you. This can avoid problems with running Dev Mode tests in your IDE, as the IDE can overwrite +the modified file with the original. + // The following link should point to the mojo page once https://github.com/quarkusio/quarkusio.github.io/issues/265 is fixed Please refer to https://github.com/quarkusio/quarkus/blob/{quarkus-version}/devtools/maven/src/main/java/io/quarkus/maven/CreateExtensionMojo.java[CreateExtensionMojo JavaDoc] for all the available options of the mojo. diff --git a/extensions/agroal/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/agroal/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/agroal/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/agroal/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/amazon-alexa/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/amazon-alexa/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/amazon-alexa/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/amazon-alexa/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/amazon-lambda-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/amazon-lambda-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/amazon-lambda-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/amazon-lambda-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/amazon-lambda-rest/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/amazon-lambda-rest/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/amazon-lambda-rest/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/amazon-lambda-rest/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/amazon-lambda-xray/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/amazon-lambda-xray/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/amazon-lambda-xray/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/amazon-lambda-xray/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/amazon-lambda/common-runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/amazon-lambda/common-runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/amazon-lambda/common-runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/amazon-lambda/common-runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/amazon-lambda/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/amazon-lambda/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/amazon-lambda/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/amazon-lambda/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/amazon-services/common/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/amazon-services/common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/amazon-services/common/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/amazon-services/common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/amazon-services/dynamodb/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/amazon-services/dynamodb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/amazon-services/dynamodb/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/amazon-services/dynamodb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/amazon-services/iam/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/amazon-services/iam/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/amazon-services/iam/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/amazon-services/iam/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/amazon-services/kms/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/amazon-services/kms/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/amazon-services/kms/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/amazon-services/kms/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/amazon-services/s3/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/amazon-services/s3/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/amazon-services/s3/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/amazon-services/s3/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/amazon-services/ses/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/amazon-services/ses/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/amazon-services/ses/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/amazon-services/ses/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/amazon-services/sns/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/amazon-services/sns/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/amazon-services/sns/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/amazon-services/sns/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/amazon-services/sqs/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/amazon-services/sqs/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/amazon-services/sqs/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/amazon-services/sqs/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/amazon-services/ssm/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/amazon-services/ssm/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/amazon-services/ssm/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/amazon-services/ssm/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/apache-httpclient/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/apache-httpclient/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/apache-httpclient/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/apache-httpclient/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/arc/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/arc/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/arc/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/arc/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/artemis-core/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/artemis-core/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/artemis-core/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/artemis-core/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/artemis-jms/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/artemis-jms/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/artemis-jms/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/artemis-jms/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/avro/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/avro/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/avro/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/avro/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/azure-functions-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/azure-functions-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/azure-functions-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/azure-functions-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/cache/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/cache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/cache/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/cache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/caffeine/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/caffeine/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/caffeine/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/caffeine/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/config-yaml/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/config-yaml/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/config-yaml/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/config-yaml/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/consul-config/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/consul-config/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/consul-config/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/consul-config/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/container-image/container-image-docker/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/container-image/container-image-docker/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/container-image/container-image-docker/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/container-image/container-image-docker/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/container-image/container-image-jib/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/container-image/container-image-jib/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/container-image/container-image-jib/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/container-image/container-image-jib/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/container-image/container-image-openshift/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/container-image/container-image-openshift/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/container-image/container-image-openshift/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/container-image/container-image-openshift/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/container-image/container-image-s2i/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/container-image/container-image-s2i/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/container-image/container-image-s2i/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/container-image/container-image-s2i/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/container-image/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/container-image/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/container-image/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/container-image/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/datasource/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/datasource/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/datasource/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/datasource/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/elasticsearch-rest-client-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/elasticsearch-rest-client-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/elasticsearch-rest-client-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/elasticsearch-rest-client-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/elasticsearch-rest-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/elasticsearch-rest-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/elasticsearch-rest-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/elasticsearch-rest-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/elasticsearch-rest-high-level-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/elasticsearch-rest-high-level-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/elasticsearch-rest-high-level-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/elasticsearch-rest-high-level-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/elytron-security-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/elytron-security-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/elytron-security-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/elytron-security-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/elytron-security-jdbc/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/elytron-security-jdbc/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/elytron-security-jdbc/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/elytron-security-jdbc/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/elytron-security-ldap/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/elytron-security-ldap/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/elytron-security-ldap/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/elytron-security-ldap/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/elytron-security-oauth2/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/elytron-security-oauth2/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/elytron-security-oauth2/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/elytron-security-oauth2/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/elytron-security-properties-file/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/elytron-security-properties-file/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/elytron-security-properties-file/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/elytron-security-properties-file/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/elytron-security/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/elytron-security/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/elytron-security/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/elytron-security/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/flyway/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/flyway/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/flyway/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/flyway/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/funqy/funqy-amazon-lambda/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/funqy/funqy-amazon-lambda/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/funqy/funqy-amazon-lambda/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/funqy/funqy-amazon-lambda/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/funqy/funqy-google-cloud-functions/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/funqy/funqy-google-cloud-functions/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/funqy/funqy-google-cloud-functions/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/funqy/funqy-google-cloud-functions/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/funqy/funqy-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/funqy/funqy-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/funqy/funqy-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/funqy/funqy-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/funqy/funqy-knative-events/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/funqy/funqy-knative-events/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/funqy/funqy-knative-events/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/funqy/funqy-knative-events/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/funqy/funqy-server-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/funqy/funqy-server-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/funqy/funqy-server-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/funqy/funqy-server-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/google-cloud-functions-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/google-cloud-functions-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/google-cloud-functions-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/google-cloud-functions-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/google-cloud-functions/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/google-cloud-functions/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/google-cloud-functions/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/google-cloud-functions/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/grpc-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/grpc-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/grpc-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/grpc-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/grpc/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/grpc/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/grpc/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/grpc/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/hibernate-envers/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/hibernate-envers/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/hibernate-envers/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/hibernate-envers/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/HibernateHotReloadTestCase.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/HibernateHotReloadTestCase.java index cb5b033cdafe8..db26b558ef50c 100644 --- a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/HibernateHotReloadTestCase.java +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/HibernateHotReloadTestCase.java @@ -17,6 +17,7 @@ import io.restassured.RestAssured; public class HibernateHotReloadTestCase { + @RegisterExtension final static QuarkusDevModeTest TEST = new QuarkusDevModeTest() .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) diff --git a/extensions/hibernate-orm/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/hibernate-orm/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/hibernate-orm/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/hibernate-orm/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/hibernate-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/hibernate-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/hibernate-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/hibernate-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/hibernate-search-orm-elasticsearch/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/hibernate-search-orm-elasticsearch/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/hibernate-validator/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/hibernate-validator/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/hibernate-validator/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/hibernate-validator/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/infinispan-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/infinispan-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/infinispan-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/infinispan-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/jaeger/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/jaeger/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/jaeger/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/jaeger/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/jaxp/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/jaxp/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/jaxp/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/jaxp/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/jdbc/jdbc-db2/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/jdbc/jdbc-db2/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/jdbc/jdbc-db2/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/jdbc/jdbc-db2/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/jdbc/jdbc-derby/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/jdbc/jdbc-derby/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/jdbc/jdbc-derby/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/jdbc/jdbc-derby/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/jdbc/jdbc-h2/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/jdbc/jdbc-h2/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/jdbc/jdbc-h2/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/jdbc/jdbc-h2/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/jdbc/jdbc-mariadb/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/jdbc/jdbc-mariadb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/jdbc/jdbc-mariadb/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/jdbc/jdbc-mariadb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/jdbc/jdbc-mssql/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/jdbc/jdbc-mssql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/jdbc/jdbc-mssql/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/jdbc/jdbc-mssql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/jdbc/jdbc-mysql/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/jdbc/jdbc-mysql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/jdbc/jdbc-mysql/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/jdbc/jdbc-mysql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/jdbc/jdbc-oracle/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/jdbc/jdbc-oracle/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/jdbc/jdbc-oracle/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/jdbc/jdbc-oracle/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/jdbc/jdbc-postgresql/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/jdbc/jdbc-postgresql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/jdbc/jdbc-postgresql/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/jdbc/jdbc-postgresql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/jgit/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/jgit/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/jgit/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/jgit/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/jsch/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/jsch/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/jsch/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/jsch/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/jsonp/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/jsonp/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/jsonp/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/jsonp/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/kafka-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/kafka-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/kafka-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/kafka-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/kafka-streams/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/kafka-streams/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/kafka-streams/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/kafka-streams/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/keycloak-admin-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/keycloak-admin-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/keycloak-admin-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/keycloak-admin-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/keycloak-authorization/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/keycloak-authorization/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/keycloak-authorization/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/keycloak-authorization/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/kubernetes-client/runtime-internal/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/kubernetes-client/runtime-internal/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/kubernetes-client/runtime-internal/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/kubernetes-client/runtime-internal/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/kubernetes-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/kubernetes-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/kubernetes-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/kubernetes-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/kubernetes-config/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/kubernetes-config/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/kubernetes-config/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/kubernetes-config/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/kubernetes-service-binding/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/kubernetes-service-binding/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/kubernetes-service-binding/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/kubernetes-service-binding/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/kubernetes/minikube/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/kubernetes/minikube/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/kubernetes/minikube/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/kubernetes/minikube/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/kubernetes/openshift/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/kubernetes/openshift/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/kubernetes/openshift/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/kubernetes/openshift/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/kubernetes/vanilla/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/kubernetes/vanilla/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/kubernetes/vanilla/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/kubernetes/vanilla/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/liquibase/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/liquibase/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/liquibase/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/liquibase/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/logging-gelf/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/logging-gelf/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/logging-gelf/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/logging-gelf/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/logging-json/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/logging-json/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/logging-json/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/logging-json/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/logging-sentry/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/logging-sentry/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/logging-sentry/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/logging-sentry/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/mailer/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/mailer/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/mailer/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/mailer/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/micrometer-registry-prometheus/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/micrometer-registry-prometheus/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/micrometer-registry-prometheus/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/micrometer-registry-prometheus/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/micrometer/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/micrometer/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/micrometer/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/micrometer/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/mongodb-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/mongodb-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/mongodb-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/mongodb-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/narayana-jta/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/narayana-jta/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/narayana-jta/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/narayana-jta/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/narayana-stm/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/narayana-stm/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/narayana-stm/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/narayana-stm/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/neo4j/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/neo4j/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/neo4j/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/neo4j/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/netty/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/netty/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/netty/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/netty/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/oidc-client-filter/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/oidc-client-filter/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/oidc-client-filter/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/oidc-client-filter/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/oidc-client-reactive-filter/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/oidc-client-reactive-filter/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/oidc-client-reactive-filter/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/oidc-client-reactive-filter/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/oidc-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/oidc-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/oidc-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/oidc-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/oidc-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/oidc-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/oidc-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/oidc-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/oidc-token-propagation/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/oidc-token-propagation/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/oidc-token-propagation/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/oidc-token-propagation/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/oidc/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/oidc/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/oidc/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/oidc/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/openshift-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/openshift-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/openshift-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/openshift-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/opentelemetry-exporter-jaeger/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/opentelemetry-exporter-jaeger/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/opentelemetry-exporter-jaeger/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/opentelemetry-exporter-jaeger/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/opentelemetry/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/opentelemetry/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/opentelemetry/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/opentelemetry/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/panache/hibernate-orm-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/panache/hibernate-orm-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/panache/hibernate-orm-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/panache/hibernate-orm-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/panache/hibernate-orm-panache-kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/panache/hibernate-orm-panache-kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/panache/hibernate-orm-panache-kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/panache/hibernate-orm-panache-kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/panache/hibernate-orm-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/panache/hibernate-orm-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/panache/hibernate-orm-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/panache/hibernate-orm-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/panache/hibernate-orm-rest-data-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/panache/hibernate-orm-rest-data-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/panache/hibernate-orm-rest-data-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/panache/hibernate-orm-rest-data-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/panache/hibernate-reactive-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/panache/hibernate-reactive-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/panache/hibernate-reactive-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/panache/hibernate-reactive-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/panache/hibernate-reactive-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/panache/hibernate-reactive-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/panache/hibernate-reactive-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/panache/hibernate-reactive-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/panache/mongodb-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/panache/mongodb-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/panache/mongodb-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/panache/mongodb-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/panache/mongodb-panache-kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/panache/mongodb-panache-kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/panache/mongodb-panache-kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/panache/mongodb-panache-kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/panache/mongodb-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/panache/mongodb-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/panache/mongodb-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/panache/mongodb-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/panache/mongodb-rest-data-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/panache/mongodb-rest-data-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/panache/mongodb-rest-data-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/panache/mongodb-rest-data-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/panache/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/panache/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/panache/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/panache/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/picocli/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/picocli/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/picocli/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/picocli/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/quartz/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/quartz/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/quartz/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/quartz/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/reactive-datasource/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/reactive-datasource/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/reactive-datasource/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/reactive-datasource/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/reactive-db2-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/reactive-db2-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/reactive-db2-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/reactive-db2-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/reactive-messaging-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/reactive-messaging-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/reactive-messaging-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/reactive-messaging-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/reactive-mysql-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/reactive-mysql-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/reactive-mysql-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/reactive-mysql-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/reactive-pg-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/reactive-pg-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/reactive-pg-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/reactive-pg-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/reactive-streams-operators/mutiny-reactive-streams-operators/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/reactive-streams-operators/mutiny-reactive-streams-operators/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/reactive-streams-operators/mutiny-reactive-streams-operators/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/reactive-streams-operators/mutiny-reactive-streams-operators/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/reactive-streams-operators/smallrye-reactive-streams-operators/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/reactive-streams-operators/smallrye-reactive-streams-operators/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/reactive-streams-operators/smallrye-reactive-streams-operators/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/reactive-streams-operators/smallrye-reactive-streams-operators/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/reactive-streams-operators/smallrye-reactive-type-converters/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/reactive-streams-operators/smallrye-reactive-type-converters/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/reactive-streams-operators/smallrye-reactive-type-converters/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/reactive-streams-operators/smallrye-reactive-type-converters/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/redis-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/redis-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/redis-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/redis-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-classic/rest-client-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-classic/rest-client-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-classic/rest-client-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-classic/rest-client-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-classic/rest-client-jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-classic/rest-client-jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-classic/rest-client-jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-classic/rest-client-jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-classic/rest-client-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-classic/rest-client-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-classic/rest-client-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-classic/rest-client-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-classic/rest-client-mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-classic/rest-client-mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-classic/rest-client-mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-classic/rest-client-mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-classic/rest-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-classic/rest-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-classic/rest-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-classic/rest-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-classic/resteasy-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-classic/resteasy-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-classic/resteasy-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-classic/resteasy-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-classic/resteasy-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-classic/resteasy-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-classic/resteasy-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-classic/resteasy-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-classic/resteasy-jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-classic/resteasy-jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-classic/resteasy-jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-classic/resteasy-jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-classic/resteasy-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-classic/resteasy-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-classic/resteasy-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-classic/resteasy-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-classic/resteasy-multipart/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-classic/resteasy-multipart/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-classic/resteasy-multipart/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-classic/resteasy-multipart/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-classic/resteasy-mutiny-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-classic/resteasy-mutiny-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-classic/resteasy-mutiny-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-classic/resteasy-mutiny-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-classic/resteasy-mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-classic/resteasy-mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-classic/resteasy-mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-classic/resteasy-mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-classic/resteasy-qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-classic/resteasy-qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-classic/resteasy-qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-classic/resteasy-qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-classic/resteasy-server-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-classic/resteasy-server-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-classic/resteasy-server-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-classic/resteasy-server-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-classic/resteasy/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-classic/resteasy/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-classic/resteasy/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-classic/resteasy/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-reactive/jaxrs-client-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-reactive/jaxrs-client-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-reactive/jaxrs-client-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-reactive/jaxrs-client-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-links/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-reactive/quarkus-resteasy-reactive-links/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-reactive/quarkus-resteasy-reactive-links/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-reactive/quarkus-resteasy-reactive-links/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-reactive/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-reactive/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-reactive/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-reactive/quarkus-resteasy-reactive-qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-reactive/quarkus-resteasy-reactive-qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-reactive/quarkus-resteasy-reactive-qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-servlet/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-reactive/quarkus-resteasy-reactive-servlet/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-reactive/quarkus-resteasy-reactive-servlet/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-reactive/quarkus-resteasy-reactive-servlet/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-reactive/rest-client-reactive-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-reactive/rest-client-reactive-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-reactive/rest-client-reactive-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-reactive/rest-client-reactive-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/scala/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/scala/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/scala/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/scala/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/scheduler/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/scheduler/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/scheduler/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/scheduler/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/security-jpa/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/security-jpa/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/security-jpa/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/security-jpa/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/security/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/security/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/security/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/security/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/smallrye-context-propagation/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/smallrye-context-propagation/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/smallrye-context-propagation/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/smallrye-context-propagation/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/smallrye-fault-tolerance/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/smallrye-fault-tolerance/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/smallrye-fault-tolerance/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/smallrye-fault-tolerance/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/smallrye-graphql/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/smallrye-graphql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/smallrye-graphql/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/smallrye-graphql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/smallrye-health/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/smallrye-health/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/smallrye-health/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/smallrye-health/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/smallrye-jwt-build/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/smallrye-jwt-build/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/smallrye-jwt-build/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/smallrye-jwt-build/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/smallrye-jwt/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/smallrye-jwt/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/smallrye-jwt/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/smallrye-jwt/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/smallrye-metrics/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/smallrye-metrics/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/smallrye-metrics/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/smallrye-metrics/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/smallrye-openapi/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/smallrye-openapi/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/smallrye-openapi/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/smallrye-openapi/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/smallrye-opentracing/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/smallrye-opentracing/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/smallrye-opentracing/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/smallrye-opentracing/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/smallrye-reactive-messaging-amqp/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/smallrye-reactive-messaging-amqp/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/smallrye-reactive-messaging-amqp/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/smallrye-reactive-messaging-amqp/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/smallrye-reactive-messaging-kafka/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/smallrye-reactive-messaging-kafka/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/smallrye-reactive-messaging-kafka/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/smallrye-reactive-messaging-kafka/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/smallrye-reactive-messaging-mqtt/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/smallrye-reactive-messaging-mqtt/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/smallrye-reactive-messaging-mqtt/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/smallrye-reactive-messaging-mqtt/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/smallrye-reactive-messaging/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/smallrye-reactive-messaging/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/smallrye-reactive-messaging/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/smallrye-reactive-messaging/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/spring-boot-properties/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/spring-boot-properties/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/spring-boot-properties/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/spring-boot-properties/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/spring-cache/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/spring-cache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/spring-cache/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/spring-cache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/spring-cloud-config-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/spring-cloud-config-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/spring-cloud-config-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/spring-cloud-config-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/spring-data-jpa/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/spring-data-jpa/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/spring-data-jpa/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/spring-data-jpa/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/spring-data-rest/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/spring-data-rest/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/spring-data-rest/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/spring-data-rest/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/spring-di/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/spring-di/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/spring-di/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/spring-di/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/spring-scheduled/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/spring-scheduled/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/spring-scheduled/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/spring-scheduled/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/spring-security/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/spring-security/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/spring-security/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/spring-security/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/spring-web/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/spring-web/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/spring-web/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/spring-web/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/swagger-ui/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/swagger-ui/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/swagger-ui/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/swagger-ui/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/tika/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/tika/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/tika/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/tika/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/undertow/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/undertow/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/undertow/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/undertow/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/vault/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/vault/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/vault/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/vault/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/vertx-core/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/vertx-core/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/vertx-core/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/vertx-core/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/vertx-graphql/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/vertx-graphql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/vertx-graphql/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/vertx-graphql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/vertx-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/vertx-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/vertx-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/vertx-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/vertx-web/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/vertx-web/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/vertx-web/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/vertx-web/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/vertx/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/vertx/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/vertx/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/vertx/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/webjars-locator/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/webjars-locator/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/webjars-locator/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/webjars-locator/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/extensions/websockets/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/websockets/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from extensions/websockets/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to extensions/websockets/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/independent-projects/bootstrap/maven-plugin/src/main/java/io/quarkus/maven/ExtensionDescriptorMojo.java b/independent-projects/bootstrap/maven-plugin/src/main/java/io/quarkus/maven/ExtensionDescriptorMojo.java index f04e504b4d504..3f9e96ca7eb4b 100644 --- a/independent-projects/bootstrap/maven-plugin/src/main/java/io/quarkus/maven/ExtensionDescriptorMojo.java +++ b/independent-projects/bootstrap/maven-plugin/src/main/java/io/quarkus/maven/ExtensionDescriptorMojo.java @@ -85,6 +85,7 @@ public class ExtensionDescriptorMojo extends AbstractMojo { private static final String GROUP_ID = "group-id"; private static final String ARTIFACT_ID = "artifact-id"; private static final String METADATA = "metadata"; + public static final String TEMPLATE = ".template"; /** * The entry point to Aether, i.e. the component doing all the work. @@ -301,19 +302,30 @@ public void execute() throws MojoExecutionException { } // extension.json + File extensionFileTemplate = null; + if (extensionFile == null) { extensionFile = new File(outputDirectory, "META-INF" + File.separator + BootstrapConstants.QUARKUS_EXTENSION_FILE_NAME); + extensionFileTemplate = new File(outputDirectory, + "META-INF" + File.separator + BootstrapConstants.QUARKUS_EXTENSION_FILE_NAME + TEMPLATE); + } else { + extensionFileTemplate = new File(extensionFile.getParent(), extensionFile.getName() + TEMPLATE); } ObjectNode extObject; - if (!extensionFile.exists()) { + if (!extensionFile.exists() && !extensionFileTemplate.exists()) { // if does not exist look for fallback .json + // template is not supported for json extensionFile = new File(extensionFile.getParent(), "quarkus-extension.json"); + extensionFileTemplate = null; } ObjectMapper mapper = null; - if (extensionFile.exists()) { + if (extensionFileTemplate != null && extensionFileTemplate.exists()) { + mapper = getMapper(true); + extObject = readJsonNode(extensionFileTemplate.toPath(), mapper); + } else if (extensionFile.exists()) { mapper = getMapper(extensionFile.toString().endsWith(".yaml")); extObject = readJsonNode(extensionFile.toPath(), mapper); } else { diff --git a/integration-tests/gradle/src/test/resources/test-resources-in-build-steps/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/integration-tests/gradle/src/test/resources/test-resources-in-build-steps/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from integration-tests/gradle/src/test/resources/test-resources-in-build-steps/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to integration-tests/gradle/src/test/resources/test-resources-in-build-steps/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template diff --git a/test-framework/jacoco/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/test-framework/jacoco/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template similarity index 100% rename from test-framework/jacoco/runtime/src/main/resources/META-INF/quarkus-extension.yaml rename to test-framework/jacoco/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template From 62640b75f26c16c10b8218936db5b954944cd323 Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Fri, 14 May 2021 14:50:47 +1000 Subject: [PATCH 0080/2077] DevServices fixes for in memory DBs - Docker is not required - Use different port for tests for Derby --- .../spi/DevServicesDatasourceProvider.java | 8 ++++++- .../DevServicesDatasourceProcessor.java | 22 +++++++++++-------- .../deployment/DB2DevServicesProcessor.java | 3 ++- .../deployment/DerbyDevServicesProcessor.java | 11 ++++++++-- .../h2/deployment/H2DevServicesProcessor.java | 8 ++++++- .../MariaDBDevServicesProcessor.java | 3 ++- .../deployment/MSSQLDevServicesProcessor.java | 3 ++- .../deployment/MySQLDevServicesProcessor.java | 3 ++- .../PostgresqlDevServicesProcessor.java | 3 ++- 9 files changed, 46 insertions(+), 18 deletions(-) diff --git a/extensions/datasource/deployment-spi/src/main/java/io/quarkus/datasource/deployment/spi/DevServicesDatasourceProvider.java b/extensions/datasource/deployment-spi/src/main/java/io/quarkus/datasource/deployment/spi/DevServicesDatasourceProvider.java index d75cc80c05cb5..151edcb39c951 100644 --- a/extensions/datasource/deployment-spi/src/main/java/io/quarkus/datasource/deployment/spi/DevServicesDatasourceProvider.java +++ b/extensions/datasource/deployment-spi/src/main/java/io/quarkus/datasource/deployment/spi/DevServicesDatasourceProvider.java @@ -5,12 +5,18 @@ import java.util.Optional; import java.util.OptionalInt; +import io.quarkus.runtime.LaunchMode; + public interface DevServicesDatasourceProvider { RunningDevServicesDatasource startDatabase(Optional username, Optional password, Optional datasourceName, Optional imageName, Map additionalProperties, - OptionalInt port); + OptionalInt port, LaunchMode launchMode); + + default boolean isDockerRequired() { + return true; + } class RunningDevServicesDatasource { diff --git a/extensions/datasource/deployment/src/main/java/io/quarkus/datasource/deployment/devservices/DevServicesDatasourceProcessor.java b/extensions/datasource/deployment/src/main/java/io/quarkus/datasource/deployment/devservices/DevServicesDatasourceProcessor.java index cb2a7eb37e479..bb0a32f22c41e 100644 --- a/extensions/datasource/deployment/src/main/java/io/quarkus/datasource/deployment/devservices/DevServicesDatasourceProcessor.java +++ b/extensions/datasource/deployment/src/main/java/io/quarkus/datasource/deployment/devservices/DevServicesDatasourceProcessor.java @@ -29,6 +29,7 @@ import io.quarkus.deployment.builditem.RunTimeConfigurationDefaultBuildItem; import io.quarkus.deployment.builditem.ServiceStartBuildItem; import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem; +import io.quarkus.runtime.LaunchMode; public class DevServicesDatasourceProcessor { @@ -112,7 +113,7 @@ DevServicesDatasourceResultBuildItem launchDatabases(CurateOutcomeBuildItem cura !dataSourceBuildTimeConfig.namedDataSources.isEmpty(), devDBProviderMap, dataSourceBuildTimeConfig.defaultDataSource, - configHandlersByDbType, propertiesMap, closeableList); + configHandlersByDbType, propertiesMap, closeableList, launchMode.getLaunchMode()); List dbConfig = new ArrayList<>(); if (defaultResult != null) { for (Map.Entry i : defaultResult.getConfigProperties().entrySet()) { @@ -122,7 +123,8 @@ DevServicesDatasourceResultBuildItem launchDatabases(CurateOutcomeBuildItem cura for (Map.Entry entry : dataSourceBuildTimeConfig.namedDataSources.entrySet()) { DevServicesDatasourceResultBuildItem.DbResult result = startDevDb(entry.getKey(), curateOutcomeBuildItem, installedDrivers, true, - devDBProviderMap, entry.getValue(), configHandlersByDbType, propertiesMap, closeableList); + devDBProviderMap, entry.getValue(), configHandlersByDbType, propertiesMap, closeableList, + launchMode.getLaunchMode()); if (result != null) { namedResults.put(entry.getKey(), result); for (Map.Entry i : result.getConfigProperties().entrySet()) { @@ -177,7 +179,8 @@ private DevServicesDatasourceResultBuildItem.DbResult startDevDb(String dbName, boolean hasNamedDatasources, Map devDBProviders, DataSourceBuildTimeConfig dataSourceBuildTimeConfig, Map> configurationHandlerBuildItems, - Map propertiesMap, List closeableList) { + Map propertiesMap, List closeableList, + LaunchMode launchMode) { Optional enabled = dataSourceBuildTimeConfig.devservices.enabled; if (enabled.isPresent() && !enabled.get()) { //explicitly disabled @@ -185,11 +188,6 @@ private DevServicesDatasourceResultBuildItem.DbResult startDevDb(String dbName, + " as it has been disabled in the config"); return null; } - if (!isDockerWorking.getAsBoolean()) { - log.warn("Please configure datasource URL for " - + (dbName == null ? "default datasource" : dbName) + " or get a working docker instance"); - return null; - } Optional defaultDbKind = DefaultDataSourceDbKindBuildItem.resolve( dataSourceBuildTimeConfig.dbKind, @@ -211,6 +209,12 @@ private DevServicesDatasourceResultBuildItem.DbResult startDevDb(String dbName, return null; } + if (devDbProvider.isDockerRequired() && !isDockerWorking.getAsBoolean()) { + log.warn("Please configure datasource URL for " + + (dbName == null ? "default datasource" : dbName) + " or get a working docker instance"); + return null; + } + if (!enabled.isPresent()) { for (DevServicesDatasourceConfigurationHandlerBuildItem i : configHandlers) { if (i.getCheckConfiguredFunction().test(dbName)) { @@ -235,7 +239,7 @@ private DevServicesDatasourceResultBuildItem.DbResult startDevDb(String dbName, ConfigProvider.getConfig().getOptionalValue(prefix + "password", String.class), Optional.ofNullable(dbName), dataSourceBuildTimeConfig.devservices.imageName, dataSourceBuildTimeConfig.devservices.properties, - dataSourceBuildTimeConfig.devservices.port); + dataSourceBuildTimeConfig.devservices.port, launchMode); closeableList.add(datasource.getCloseTask()); Map devDebProperties = new HashMap<>(); diff --git a/extensions/devservices/db2/src/main/java/io/quarkus/devservices/db2/deployment/DB2DevServicesProcessor.java b/extensions/devservices/db2/src/main/java/io/quarkus/devservices/db2/deployment/DB2DevServicesProcessor.java index ca5711f07983c..c18a7453dda7f 100644 --- a/extensions/devservices/db2/src/main/java/io/quarkus/devservices/db2/deployment/DB2DevServicesProcessor.java +++ b/extensions/devservices/db2/src/main/java/io/quarkus/devservices/db2/deployment/DB2DevServicesProcessor.java @@ -13,6 +13,7 @@ import io.quarkus.datasource.deployment.spi.DevServicesDatasourceProvider; import io.quarkus.datasource.deployment.spi.DevServicesDatasourceProviderBuildItem; import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.runtime.LaunchMode; public class DB2DevServicesProcessor { @@ -27,7 +28,7 @@ DevServicesDatasourceProviderBuildItem setupDB2() { @Override public RunningDevServicesDatasource startDatabase(Optional username, Optional password, Optional datasourceName, Optional imageName, Map additionalProperties, - OptionalInt fixedExposedPort) { + OptionalInt fixedExposedPort, LaunchMode launchMode) { Db2Container container = new Db2Container( DockerImageName.parse(imageName.orElse("ibmcom/db2:" + TAG)) .asCompatibleSubstituteFor(DockerImageName.parse("ibmcom/db2"))) { diff --git a/extensions/devservices/derby/src/main/java/io/quarkus/devservices/postgresql/deployment/DerbyDevServicesProcessor.java b/extensions/devservices/derby/src/main/java/io/quarkus/devservices/postgresql/deployment/DerbyDevServicesProcessor.java index dd5e8602ae21b..4a71ac0e4a4ab 100644 --- a/extensions/devservices/derby/src/main/java/io/quarkus/devservices/postgresql/deployment/DerbyDevServicesProcessor.java +++ b/extensions/devservices/derby/src/main/java/io/quarkus/devservices/postgresql/deployment/DerbyDevServicesProcessor.java @@ -14,6 +14,7 @@ import io.quarkus.datasource.deployment.spi.DevServicesDatasourceProvider; import io.quarkus.datasource.deployment.spi.DevServicesDatasourceProviderBuildItem; import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.runtime.LaunchMode; public class DerbyDevServicesProcessor { @@ -26,9 +27,10 @@ DevServicesDatasourceProviderBuildItem setupDerby() { @Override public RunningDevServicesDatasource startDatabase(Optional username, Optional password, Optional datasourceName, Optional imageName, Map additionalProperties, - OptionalInt fixedExposedPort) { + OptionalInt fixedExposedPort, LaunchMode launchMode) { try { - int port = fixedExposedPort.isPresent() ? fixedExposedPort.getAsInt() : 1527; + int port = fixedExposedPort.isPresent() ? fixedExposedPort.getAsInt() + : 1527 + (launchMode == LaunchMode.TEST ? 0 : 1); NetworkServerControl server = new NetworkServerControl(InetAddress.getByName("localhost"), port); server.start(new PrintWriter(System.out)); for (int i = 1; i <= NUMBER_OF_PINGS; i++) { @@ -77,6 +79,11 @@ public void close() throws IOException { throw new RuntimeException(throwable); } } + + @Override + public boolean isDockerRequired() { + return false; + } }); } } diff --git a/extensions/devservices/h2/src/main/java/io/quarkus/devservices/h2/deployment/H2DevServicesProcessor.java b/extensions/devservices/h2/src/main/java/io/quarkus/devservices/h2/deployment/H2DevServicesProcessor.java index d7732f7ff2a7b..bd0889a21e54e 100644 --- a/extensions/devservices/h2/src/main/java/io/quarkus/devservices/h2/deployment/H2DevServicesProcessor.java +++ b/extensions/devservices/h2/src/main/java/io/quarkus/devservices/h2/deployment/H2DevServicesProcessor.java @@ -16,6 +16,7 @@ import io.quarkus.datasource.deployment.spi.DevServicesDatasourceProvider; import io.quarkus.datasource.deployment.spi.DevServicesDatasourceProviderBuildItem; import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.runtime.LaunchMode; public class H2DevServicesProcessor { @@ -25,7 +26,7 @@ DevServicesDatasourceProviderBuildItem setupH2() { @Override public RunningDevServicesDatasource startDatabase(Optional username, Optional password, Optional datasourceName, Optional imageName, Map additionalProperties, - OptionalInt port) { + OptionalInt port, LaunchMode launchMode) { try { final Server tcpServer = Server.createTcpServer("-tcpPort", port.isPresent() ? String.valueOf(port.getAsInt()) : "0"); @@ -67,6 +68,11 @@ public void close() throws IOException { throw new RuntimeException(throwables); } } + + @Override + public boolean isDockerRequired() { + return false; + } }); } } diff --git a/extensions/devservices/mariadb/src/main/java/io/quarkus/devservices/postgresql/deployment/MariaDBDevServicesProcessor.java b/extensions/devservices/mariadb/src/main/java/io/quarkus/devservices/postgresql/deployment/MariaDBDevServicesProcessor.java index cf993f100c76c..39834f4b0aba8 100644 --- a/extensions/devservices/mariadb/src/main/java/io/quarkus/devservices/postgresql/deployment/MariaDBDevServicesProcessor.java +++ b/extensions/devservices/mariadb/src/main/java/io/quarkus/devservices/postgresql/deployment/MariaDBDevServicesProcessor.java @@ -13,6 +13,7 @@ import io.quarkus.datasource.deployment.spi.DevServicesDatasourceProvider; import io.quarkus.datasource.deployment.spi.DevServicesDatasourceProviderBuildItem; import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.runtime.LaunchMode; public class MariaDBDevServicesProcessor { @@ -24,7 +25,7 @@ DevServicesDatasourceProviderBuildItem setupMariaDB() { @Override public RunningDevServicesDatasource startDatabase(Optional username, Optional password, Optional datasourceName, Optional imageName, Map additionalProperties, - OptionalInt fixedExposedPort) { + OptionalInt fixedExposedPort, LaunchMode launchMode) { MariaDBContainer container = new MariaDBContainer( DockerImageName.parse(imageName.orElse(MariaDBContainer.IMAGE + ":" + TAG)) .asCompatibleSubstituteFor(DockerImageName.parse(MariaDBContainer.IMAGE))) { diff --git a/extensions/devservices/mssql/src/main/java/io/quarkus/devservices/mssql/deployment/MSSQLDevServicesProcessor.java b/extensions/devservices/mssql/src/main/java/io/quarkus/devservices/mssql/deployment/MSSQLDevServicesProcessor.java index 4973c4cc4642c..9ad0aecea26f2 100644 --- a/extensions/devservices/mssql/src/main/java/io/quarkus/devservices/mssql/deployment/MSSQLDevServicesProcessor.java +++ b/extensions/devservices/mssql/src/main/java/io/quarkus/devservices/mssql/deployment/MSSQLDevServicesProcessor.java @@ -14,6 +14,7 @@ import io.quarkus.datasource.deployment.spi.DevServicesDatasourceProvider; import io.quarkus.datasource.deployment.spi.DevServicesDatasourceProviderBuildItem; import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.runtime.LaunchMode; public class MSSQLDevServicesProcessor { @@ -28,7 +29,7 @@ DevServicesDatasourceProviderBuildItem setupMSSQL() { @Override public RunningDevServicesDatasource startDatabase(Optional username, Optional password, Optional datasourceName, Optional imageName, Map additionalProperties, - OptionalInt fixedExposedPort) { + OptionalInt fixedExposedPort, LaunchMode launchMode) { JdbcDatabaseContainer container = new MSSQLServerContainer( DockerImageName .parse(imageName.orElse(MSSQLServerContainer.IMAGE + ":" + TAG)) diff --git a/extensions/devservices/mysql/src/main/java/io/quarkus/devservices/postgresql/deployment/MySQLDevServicesProcessor.java b/extensions/devservices/mysql/src/main/java/io/quarkus/devservices/postgresql/deployment/MySQLDevServicesProcessor.java index 706eed8940553..7846f1716987d 100644 --- a/extensions/devservices/mysql/src/main/java/io/quarkus/devservices/postgresql/deployment/MySQLDevServicesProcessor.java +++ b/extensions/devservices/mysql/src/main/java/io/quarkus/devservices/postgresql/deployment/MySQLDevServicesProcessor.java @@ -13,6 +13,7 @@ import io.quarkus.datasource.deployment.spi.DevServicesDatasourceProvider; import io.quarkus.datasource.deployment.spi.DevServicesDatasourceProviderBuildItem; import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.runtime.LaunchMode; public class MySQLDevServicesProcessor { @@ -24,7 +25,7 @@ DevServicesDatasourceProviderBuildItem setupMysql() { @Override public RunningDevServicesDatasource startDatabase(Optional username, Optional password, Optional datasourceName, Optional imageName, Map additionalProperties, - OptionalInt fixedExposedPort) { + OptionalInt fixedExposedPort, LaunchMode launchMode) { MySQLContainer container = new MySQLContainer( DockerImageName.parse(imageName.orElse(MySQLContainer.IMAGE + ":" + TAG)) .asCompatibleSubstituteFor(DockerImageName.parse(MySQLContainer.IMAGE))) { diff --git a/extensions/devservices/postgresql/src/main/java/io/quarkus/devservices/postgresql/deployment/PostgresqlDevServicesProcessor.java b/extensions/devservices/postgresql/src/main/java/io/quarkus/devservices/postgresql/deployment/PostgresqlDevServicesProcessor.java index 6eee877e897b1..8fb3c5b460e38 100644 --- a/extensions/devservices/postgresql/src/main/java/io/quarkus/devservices/postgresql/deployment/PostgresqlDevServicesProcessor.java +++ b/extensions/devservices/postgresql/src/main/java/io/quarkus/devservices/postgresql/deployment/PostgresqlDevServicesProcessor.java @@ -13,6 +13,7 @@ import io.quarkus.datasource.deployment.spi.DevServicesDatasourceProvider; import io.quarkus.datasource.deployment.spi.DevServicesDatasourceProviderBuildItem; import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.runtime.LaunchMode; public class PostgresqlDevServicesProcessor { @@ -24,7 +25,7 @@ DevServicesDatasourceProviderBuildItem setupPostgres() { @Override public RunningDevServicesDatasource startDatabase(Optional username, Optional password, Optional datasourceName, Optional imageName, Map additionalProperties, - OptionalInt fixedExposedPort) { + OptionalInt fixedExposedPort, LaunchMode launchMode) { PostgreSQLContainer container = new PostgreSQLContainer( DockerImageName.parse(imageName.orElse(PostgreSQLContainer.IMAGE + ":" + TAG)) .asCompatibleSubstituteFor(DockerImageName.parse(PostgreSQLContainer.IMAGE))) { From d68020cc7af16ea898da5607a983252115f154a9 Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Fri, 14 May 2021 17:42:40 +1000 Subject: [PATCH 0081/2077] Rename DevConsoleProcessor Its annoying to have so many classes with the same name. --- .../{DevConsoleProcessor.java => ArcDevConsoleProcessor.java} | 2 +- .../{DevConsoleProcessor.java => CacheDevConsoleProcessor.java} | 2 +- ...{DevConsoleProcessor.java => FlywayDevConsoleProcessor.java} | 2 +- ...ava => HibernateSearchElasticsearchDevConsoleProcessor.java} | 2 +- ...vConsoleProcessor.java => LiquibaseDevConsoleProcessor.java} | 2 +- .../{DevConsoleProcessor.java => QuteDevConsoleProcessor.java} | 2 +- ...eProcessor.java => ResteasyReactiveDevConsoleProcessor.java} | 2 +- ...Processor.java => ReactiveMessagingDevConsoleProcessor.java} | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) rename extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/{DevConsoleProcessor.java => ArcDevConsoleProcessor.java} (99%) rename extensions/cache/deployment/src/main/java/io/quarkus/cache/deployment/devconsole/{DevConsoleProcessor.java => CacheDevConsoleProcessor.java} (96%) rename extensions/flyway/deployment/src/main/java/io/quarkus/flyway/devconsole/{DevConsoleProcessor.java => FlywayDevConsoleProcessor.java} (96%) rename extensions/hibernate-search-orm-elasticsearch/deployment/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/devconsole/{DevConsoleProcessor.java => HibernateSearchElasticsearchDevConsoleProcessor.java} (94%) rename extensions/liquibase/deployment/src/main/java/io/quarkus/liquibase/deployment/devconsole/{DevConsoleProcessor.java => LiquibaseDevConsoleProcessor.java} (95%) rename extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/devconsole/{DevConsoleProcessor.java => QuteDevConsoleProcessor.java} (98%) rename extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/devconsole/{DevConsoleProcessor.java => ResteasyReactiveDevConsoleProcessor.java} (98%) rename extensions/smallrye-reactive-messaging/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/deployment/devconsole/{DevConsoleProcessor.java => ReactiveMessagingDevConsoleProcessor.java} (98%) diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/DevConsoleProcessor.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/ArcDevConsoleProcessor.java similarity index 99% rename from extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/DevConsoleProcessor.java rename to extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/ArcDevConsoleProcessor.java index f3235148f9b98..6aa525cec7768 100644 --- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/DevConsoleProcessor.java +++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/ArcDevConsoleProcessor.java @@ -35,7 +35,7 @@ import io.quarkus.devconsole.spi.DevConsoleRuntimeTemplateInfoBuildItem; import io.quarkus.devconsole.spi.DevConsoleTemplateInfoBuildItem; -public class DevConsoleProcessor { +public class ArcDevConsoleProcessor { @BuildStep(onlyIf = IsDevelopment.class) @Record(ExecutionTime.STATIC_INIT) diff --git a/extensions/cache/deployment/src/main/java/io/quarkus/cache/deployment/devconsole/DevConsoleProcessor.java b/extensions/cache/deployment/src/main/java/io/quarkus/cache/deployment/devconsole/CacheDevConsoleProcessor.java similarity index 96% rename from extensions/cache/deployment/src/main/java/io/quarkus/cache/deployment/devconsole/DevConsoleProcessor.java rename to extensions/cache/deployment/src/main/java/io/quarkus/cache/deployment/devconsole/CacheDevConsoleProcessor.java index f079dc2758f7a..12926396dd757 100644 --- a/extensions/cache/deployment/src/main/java/io/quarkus/cache/deployment/devconsole/DevConsoleProcessor.java +++ b/extensions/cache/deployment/src/main/java/io/quarkus/cache/deployment/devconsole/CacheDevConsoleProcessor.java @@ -10,7 +10,7 @@ import io.quarkus.devconsole.spi.DevConsoleRouteBuildItem; import io.quarkus.devconsole.spi.DevConsoleRuntimeTemplateInfoBuildItem; -public class DevConsoleProcessor { +public class CacheDevConsoleProcessor { @BuildStep(onlyIf = IsDevelopment.class) public DevConsoleRuntimeTemplateInfoBuildItem collectBeanInfo() { diff --git a/extensions/flyway/deployment/src/main/java/io/quarkus/flyway/devconsole/DevConsoleProcessor.java b/extensions/flyway/deployment/src/main/java/io/quarkus/flyway/devconsole/FlywayDevConsoleProcessor.java similarity index 96% rename from extensions/flyway/deployment/src/main/java/io/quarkus/flyway/devconsole/DevConsoleProcessor.java rename to extensions/flyway/deployment/src/main/java/io/quarkus/flyway/devconsole/FlywayDevConsoleProcessor.java index aecea63259004..0d87e686216a8 100644 --- a/extensions/flyway/deployment/src/main/java/io/quarkus/flyway/devconsole/DevConsoleProcessor.java +++ b/extensions/flyway/deployment/src/main/java/io/quarkus/flyway/devconsole/FlywayDevConsoleProcessor.java @@ -10,7 +10,7 @@ import io.quarkus.flyway.runtime.FlywayContainersSupplier; import io.quarkus.flyway.runtime.devconsole.FlywayDevConsoleRecorder; -public class DevConsoleProcessor { +public class FlywayDevConsoleProcessor { @BuildStep(onlyIf = IsDevelopment.class) public DevConsoleRuntimeTemplateInfoBuildItem collectBeanInfo() { diff --git a/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/devconsole/DevConsoleProcessor.java b/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/devconsole/HibernateSearchElasticsearchDevConsoleProcessor.java similarity index 94% rename from extensions/hibernate-search-orm-elasticsearch/deployment/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/devconsole/DevConsoleProcessor.java rename to extensions/hibernate-search-orm-elasticsearch/deployment/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/devconsole/HibernateSearchElasticsearchDevConsoleProcessor.java index a4e2f90932ed4..e77c3b5bd5044 100644 --- a/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/devconsole/DevConsoleProcessor.java +++ b/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/devconsole/HibernateSearchElasticsearchDevConsoleProcessor.java @@ -10,7 +10,7 @@ import io.quarkus.hibernate.search.orm.elasticsearch.runtime.devconsole.HibernateSearchDevConsoleRecorder; import io.quarkus.hibernate.search.orm.elasticsearch.runtime.devconsole.HibernateSearchSupplier; -public class DevConsoleProcessor { +public class HibernateSearchElasticsearchDevConsoleProcessor { @BuildStep(onlyIf = IsDevelopment.class) public DevConsoleRuntimeTemplateInfoBuildItem collectBeanInfo() { diff --git a/extensions/liquibase/deployment/src/main/java/io/quarkus/liquibase/deployment/devconsole/DevConsoleProcessor.java b/extensions/liquibase/deployment/src/main/java/io/quarkus/liquibase/deployment/devconsole/LiquibaseDevConsoleProcessor.java similarity index 95% rename from extensions/liquibase/deployment/src/main/java/io/quarkus/liquibase/deployment/devconsole/DevConsoleProcessor.java rename to extensions/liquibase/deployment/src/main/java/io/quarkus/liquibase/deployment/devconsole/LiquibaseDevConsoleProcessor.java index c585116d19993..210bbf5e01eaf 100644 --- a/extensions/liquibase/deployment/src/main/java/io/quarkus/liquibase/deployment/devconsole/DevConsoleProcessor.java +++ b/extensions/liquibase/deployment/src/main/java/io/quarkus/liquibase/deployment/devconsole/LiquibaseDevConsoleProcessor.java @@ -10,7 +10,7 @@ import io.quarkus.liquibase.runtime.devconsole.LiquibaseDevConsoleRecorder; import io.quarkus.liquibase.runtime.devconsole.LiquibaseFactoriesSupplier; -public class DevConsoleProcessor { +public class LiquibaseDevConsoleProcessor { @BuildStep(onlyIf = IsDevelopment.class) public DevConsoleRuntimeTemplateInfoBuildItem collectBeanInfo() { diff --git a/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/devconsole/DevConsoleProcessor.java b/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/devconsole/QuteDevConsoleProcessor.java similarity index 98% rename from extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/devconsole/DevConsoleProcessor.java rename to extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/devconsole/QuteDevConsoleProcessor.java index 3f2b744cae8ae..730c9fc40d5ff 100644 --- a/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/devconsole/DevConsoleProcessor.java +++ b/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/devconsole/QuteDevConsoleProcessor.java @@ -10,7 +10,7 @@ import io.quarkus.qute.deployment.TemplatePathBuildItem; import io.quarkus.qute.deployment.TemplateVariantsBuildItem; -public class DevConsoleProcessor { +public class QuteDevConsoleProcessor { @BuildStep(onlyIf = IsDevelopment.class) public DevConsoleTemplateInfoBuildItem collectTemplateInfo( diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/devconsole/DevConsoleProcessor.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/devconsole/ResteasyReactiveDevConsoleProcessor.java similarity index 98% rename from extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/devconsole/DevConsoleProcessor.java rename to extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/devconsole/ResteasyReactiveDevConsoleProcessor.java index bcf7f2fa5a8e4..ad1e7bb0c9feb 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/devconsole/DevConsoleProcessor.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/devconsole/ResteasyReactiveDevConsoleProcessor.java @@ -21,7 +21,7 @@ import io.quarkus.vertx.http.deployment.devmode.NotFoundPageDisplayableEndpointBuildItem; import io.quarkus.vertx.http.runtime.StaticResourcesRecorder; -public class DevConsoleProcessor { +public class ResteasyReactiveDevConsoleProcessor { @BuildStep(onlyIf = IsDevelopment.class) public DevConsoleRuntimeTemplateInfoBuildItem collectScores() { diff --git a/extensions/smallrye-reactive-messaging/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/deployment/devconsole/DevConsoleProcessor.java b/extensions/smallrye-reactive-messaging/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/deployment/devconsole/ReactiveMessagingDevConsoleProcessor.java similarity index 98% rename from extensions/smallrye-reactive-messaging/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/deployment/devconsole/DevConsoleProcessor.java rename to extensions/smallrye-reactive-messaging/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/deployment/devconsole/ReactiveMessagingDevConsoleProcessor.java index 7e84c25dfa085..5545034dee8b8 100644 --- a/extensions/smallrye-reactive-messaging/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/deployment/devconsole/DevConsoleProcessor.java +++ b/extensions/smallrye-reactive-messaging/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/deployment/devconsole/ReactiveMessagingDevConsoleProcessor.java @@ -19,7 +19,7 @@ import io.quarkus.smallrye.reactivemessaging.runtime.devconsole.DevConsoleRecorder; import io.quarkus.smallrye.reactivemessaging.runtime.devconsole.DevReactiveMessagingInfosSupplier; -public class DevConsoleProcessor { +public class ReactiveMessagingDevConsoleProcessor { @BuildStep(onlyIf = IsDevelopment.class) public DevConsoleRuntimeTemplateInfoBuildItem collectInfos() { From 3ee14dd38a7d1437ae643000620c9e7afe294a6d Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Fri, 14 May 2021 10:40:43 +0200 Subject: [PATCH 0082/2077] Load base codestarts before extra codestarts The precedence for the loaded codestarts should be `extensions < base < catalog < extra` so that the codestarts in the platform (i.e. catalog) and the extra provided codestarts can override any of the extension and base codestarts. This was not the case for base codestarts, which could not be overridden at all. --- .../CodestartResourceLoadersBuilder.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/CodestartResourceLoadersBuilder.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/CodestartResourceLoadersBuilder.java index 97612e9d3be84..1959a4b97177b 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/CodestartResourceLoadersBuilder.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/CodestartResourceLoadersBuilder.java @@ -96,19 +96,11 @@ public List build() { } private static List getCodestartResourceLoaders(String baseCodestartsArtifactCoords, - Collection extraCodestartsArtifactCoords, ExtensionCatalog catalog, - MavenArtifactResolver artifactResolver) { - final List coords = new ArrayList<>(extraCodestartsArtifactCoords); - if (baseCodestartsArtifactCoords != null) { - coords.add(baseCodestartsArtifactCoords); - } - return getCodestartResourceLoaders(coords, catalog, artifactResolver); - } - - private static List getCodestartResourceLoaders(Collection extraCodestartsArtifactCoords, + Collection extraCodestartsArtifactCoords, ExtensionCatalog catalog, MavenArtifactResolver mvn) { final Map codestartsArtifacts = new LinkedHashMap<>(); + if (catalog != null) { // Load codestarts from each extensions codestart artifacts for (Extension e : catalog.getExtensions()) { @@ -118,7 +110,14 @@ private static List getCodestartResourceLoaders(Collection catalogCodestartArtifacts = getCodestartArtifacts(catalog); for (String artifactCoords : catalogCodestartArtifacts) { @@ -128,6 +127,7 @@ private static List getCodestartResourceLoaders(Collection Date: Fri, 14 May 2021 13:30:11 +0200 Subject: [PATCH 0083/2077] gRPC always start server in development mode --- .../java/io/quarkus/grpc/deployment/GrpcServerProcessor.java | 4 +++- .../main/java/io/quarkus/grpc/runtime/GrpcServerRecorder.java | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcServerProcessor.java b/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcServerProcessor.java index a7cfb664d37a8..f59d09c1a5fbf 100644 --- a/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcServerProcessor.java +++ b/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcServerProcessor.java @@ -48,6 +48,7 @@ import io.quarkus.grpc.runtime.supports.context.GrpcRequestContextCdiInterceptor; import io.quarkus.kubernetes.spi.KubernetesPortBuildItem; import io.quarkus.netty.deployment.MinNettyAllocatorMaxOrderBuildItem; +import io.quarkus.runtime.LaunchMode; import io.quarkus.smallrye.health.deployment.spi.HealthBuildItem; import io.quarkus.vertx.deployment.VertxBuildItem; @@ -120,7 +121,8 @@ void registerBeans(BuildProducer beans, beans.produce(new AdditionalBeanBuildItem(GrpcService.class)); beans.produce(new AdditionalBeanBuildItem(GrpcRequestContextCdiInterceptor.class)); beans.produce(new AdditionalBeanBuildItem(GrpcEnableRequestContext.class)); - if (!bindables.isEmpty()) { + + if (!bindables.isEmpty() || LaunchMode.current() == LaunchMode.DEVELOPMENT) { beans.produce(AdditionalBeanBuildItem.unremovableOf(GrpcContainer.class)); features.produce(new FeatureBuildItem(GRPC_SERVER)); } else { diff --git a/extensions/grpc/runtime/src/main/java/io/quarkus/grpc/runtime/GrpcServerRecorder.java b/extensions/grpc/runtime/src/main/java/io/quarkus/grpc/runtime/GrpcServerRecorder.java index 6aa081bc8209c..878e3a13f7bab 100644 --- a/extensions/grpc/runtime/src/main/java/io/quarkus/grpc/runtime/GrpcServerRecorder.java +++ b/extensions/grpc/runtime/src/main/java/io/quarkus/grpc/runtime/GrpcServerRecorder.java @@ -77,7 +77,7 @@ public void initializeGrpcServer(RuntimeValue vertxSupplier, throw new IllegalStateException("gRPC not initialized, GrpcContainer not found"); } Vertx vertx = vertxSupplier.getValue(); - if (hasNoServices(grpcContainer.getServices())) { + if (hasNoServices(grpcContainer.getServices()) && LaunchMode.current() != LaunchMode.DEVELOPMENT) { throw new IllegalStateException( "Unable to find beans exposing the `BindableService` interface - not starting the gRPC server"); } From d887cede16768692de12b0fcf7ab28025b83f605 Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Fri, 7 May 2021 14:40:58 +0100 Subject: [PATCH 0084/2077] Make client-id optional for OIDC service applications --- .../asciidoc/security-openid-connect.adoc | 24 +++++++++++++++++ .../client/runtime/OidcClientRecorder.java | 2 +- .../oidc/common/runtime/OidcCommonUtils.java | 12 ++++++--- .../io/quarkus/oidc/runtime/OidcProvider.java | 6 ++++- .../io/quarkus/oidc/runtime/OidcRecorder.java | 12 ++++++--- .../src/main/resources/application.properties | 4 +++ .../BearerTokenAuthorizationTest.java | 27 ++++++++++++++++++- .../KeycloakRealmResourceManager.java | 3 +++ 8 files changed, 80 insertions(+), 10 deletions(-) diff --git a/docs/src/main/asciidoc/security-openid-connect.adoc b/docs/src/main/asciidoc/security-openid-connect.adoc index f891aa99637df..6d8a032c1027e 100644 --- a/docs/src/main/asciidoc/security-openid-connect.adoc +++ b/docs/src/main/asciidoc/security-openid-connect.adoc @@ -786,6 +786,30 @@ Note that the OpenId Connect Provider externally accessible token and other endp In such cases, if you work with Keycloak then please start it with a `KEYCLOAK_FRONTEND_URL` system property set to the externally accessible base URL. If you work with other Openid Connect providers then please check your provider's documentation. +== How to use 'client-id' property + +`quarkus.oidc.client-id` property identifies an OpenId Connect Client which requested the current bearer token. It can be an SPA application running in a browser or a Quarkus `web-app` confidential client application propagating the access token to the Quarkus `service` application. + +This property is required if the `service` application is expected to introspect the tokens remotely - which is always the case for the opaque tokens. +This property is optional if the local Json Web Key token verification only is used. + +Nonetheless, setting this propery is encouraged even if the endpoint does not require an access to the remote introspection endpoint. The reasons behind it that `client-id`, if set, can be used to verify the token audience and will also be included in the logs when the token verification fails for the better traceability of the tokens issued to specific clients to be analyzed over a longer period of time. + +For example, if your OpenId Connect provider sets a token audience then the following configuration pattern is recommended: + +[source, properties] +---- +# Set client-id +quarkus.oidc.client-id=quarkus-app +# Token audience claim must contain 'quarkus-app' +quarkus.oidc.token.audience=${quarkus.oidc.client-id} +---- + +If you set `quarkus.oidc.client-id` but your endpoint does not require a remote access to one of OpenId Connect Provider endpoints (introspection, token acquisition, etc) then do not set a client secret with the `quarkus.oidc.credentials` or similar properties as it will not be used. + +Note Quarkus `web-app` applications always require `quarkus.oidc.client-id` property. + + == References * https://www.keycloak.org/documentation.html[Keycloak Documentation] diff --git a/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientRecorder.java b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientRecorder.java index bc884ba8b6b48..7afcd0079e0d7 100644 --- a/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientRecorder.java +++ b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientRecorder.java @@ -107,7 +107,7 @@ protected static Uni createOidcClientUni(OidcClientConfig oidcConfig } try { - OidcCommonUtils.verifyCommonConfiguration(oidcConfig, false); + OidcCommonUtils.verifyCommonConfiguration(oidcConfig, false, false); } catch (Throwable t) { LOG.debug(t.getMessage()); String message = String.format("'%s' client configuration is not initialized", oidcClientId); diff --git a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcCommonUtils.java b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcCommonUtils.java index 79b574c74cd16..07afca118ec3b 100644 --- a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcCommonUtils.java +++ b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcCommonUtils.java @@ -36,14 +36,20 @@ private OidcCommonUtils() { } - public static void verifyCommonConfiguration(OidcCommonConfig oidcConfig, boolean isServerConfig) { + public static void verifyCommonConfiguration(OidcCommonConfig oidcConfig, boolean clientIdOptional, + boolean isServerConfig) { final String configPrefix = isServerConfig ? "quarkus.oidc." : "quarkus.oidc-client."; - if (!oidcConfig.getAuthServerUrl().isPresent() || !oidcConfig.getClientId().isPresent()) { + if (!oidcConfig.getAuthServerUrl().isPresent()) { throw new ConfigurationException( - String.format("Both '%1$sauth-server-url' and '%1$sclient-id' properties must be configured", + String.format("'%sauth-server-url' property must be configured", configPrefix)); } + if (!clientIdOptional && !oidcConfig.getClientId().isPresent()) { + throw new ConfigurationException( + String.format("'%sclient-id' property must be configured", configPrefix)); + } + try { // Verify that auth-server-url is a valid URL URI.create(oidcConfig.getAuthServerUrl().get()).toURL(); diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProvider.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProvider.java index 811acc07bfc71..b92382ade854c 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProvider.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProvider.java @@ -117,7 +117,11 @@ public TokenVerificationResult verifyJwtToken(String token) throws InvalidJwtExc if (!details.isEmpty()) { detail = details.get(0).getErrorMessage(); } - LOG.debugf("Token verification has failed: %s", detail); + if (oidcConfig.clientId.isPresent()) { + LOG.debugf("Verification of the token issued to client %s has failed: %s", oidcConfig.clientId.get(), detail); + } else { + LOG.debugf("Token verification has failed: %s", detail); + } throw ex; } return new TokenVerificationResult(OidcUtils.decodeJwtContent(token), null); diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcRecorder.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcRecorder.java index 55719d0d1c59f..22f7ef674f123 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcRecorder.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcRecorder.java @@ -147,13 +147,13 @@ private Uni createTenantContext(Vertx vertx, OidcTenantConf } try { - OidcCommonUtils.verifyCommonConfiguration(oidcConfig, true); + OidcCommonUtils.verifyCommonConfiguration(oidcConfig, isServiceApp(oidcConfig), true); } catch (ConfigurationException t) { return Uni.createFrom().failure(t); } if (!oidcConfig.discoveryEnabled) { - if (oidcConfig.applicationType != ApplicationType.SERVICE) { + if (!isServiceApp(oidcConfig)) { if (!oidcConfig.authorizationPath.isPresent() || !oidcConfig.tokenPath.isPresent()) { throw new OIDCException("'web-app' applications must have 'authorization-path' and 'token-path' properties " + "set when the discovery is disabled."); @@ -166,7 +166,7 @@ private Uni createTenantContext(Vertx vertx, OidcTenantConf } } - if (ApplicationType.SERVICE.equals(oidcConfig.applicationType)) { + if (isServiceApp(oidcConfig)) { if (oidcConfig.token.refreshExpired) { throw new ConfigurationException( "The 'token.refresh-expired' property can only be enabled for " + ApplicationType.WEB_APP @@ -201,7 +201,7 @@ private Uni createTenantContext(Vertx vertx, OidcTenantConf } private static TenantConfigContext createTenantContextFromPublicKey(OidcTenantConfig oidcConfig) { - if (oidcConfig.applicationType != ApplicationType.SERVICE) { + if (!isServiceApp(oidcConfig)) { throw new ConfigurationException("'public-key' property can only be used with the 'service' applications"); } LOG.debug("'public-key' property for the local token verification is set," @@ -317,4 +317,8 @@ private static Uni discoverMetadata(WebClient client, }); } + private static boolean isServiceApp(OidcTenantConfig oidcConfig) { + return ApplicationType.SERVICE.equals(oidcConfig.applicationType); + } + } diff --git a/integration-tests/oidc-tenancy/src/main/resources/application.properties b/integration-tests/oidc-tenancy/src/main/resources/application.properties index e4c08bb0e4399..53b83fa9c91d8 100644 --- a/integration-tests/oidc-tenancy/src/main/resources/application.properties +++ b/integration-tests/oidc-tenancy/src/main/resources/application.properties @@ -13,6 +13,10 @@ quarkus.oidc.tenant-b.credentials.secret=secret quarkus.oidc.tenant-b.token.issuer=${keycloak.url}/realms/quarkus-b quarkus.oidc.tenant-b.application-type=service +# Tenant B - 2 clients +quarkus.oidc.tenant-b2.auth-server-url=${keycloak.url}/realms/quarkus-b +# issuer is discovered + # Tenant B Service No Discovery (Introspection + User Info) quarkus.oidc.tenant-b-no-discovery.auth-server-url=${keycloak.url}/realms/quarkus-b quarkus.oidc.tenant-b-no-discovery.discovery-enabled=false diff --git a/integration-tests/oidc-tenancy/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java b/integration-tests/oidc-tenancy/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java index ab0629e3e3660..ea61909f7e595 100644 --- a/integration-tests/oidc-tenancy/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java +++ b/integration-tests/oidc-tenancy/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java @@ -156,6 +156,27 @@ public void testReAuthenticateWhenSwitchingTenants() throws IOException { } } + @Test + public void testTenantBAllClients() { + RestAssured.given().auth().oauth2(getAccessToken("alice", "b")) + .when().get("/tenant/tenant-b2/api/user") + .then() + .statusCode(200) + .body(equalTo("tenant-b2:alice")); + + RestAssured.given().auth().oauth2(getAccessToken("alice", "b", "b2")) + .when().get("/tenant/tenant-b2/api/user") + .then() + .statusCode(200) + .body(equalTo("tenant-b2:alice")); + + // should give a 401 given that access token from issuer c can not access tenant b + RestAssured.given().auth().oauth2(getAccessToken("alice", "c")) + .when().get("/tenant/tenant-b2/api/user") + .then() + .statusCode(401); + } + @Test public void testResolveTenantIdentifier() { RestAssured.given().auth().oauth2(getAccessToken("alice", "b")) @@ -353,6 +374,10 @@ public void testResolveTenantIdentifierWebAppDynamic() throws IOException { } private String getAccessToken(String userName, String clientId) { + return getAccessToken(userName, clientId, clientId); + } + + private String getAccessToken(String userName, String realmId, String clientId) { return RestAssured .given() .param("grant_type", "password") @@ -361,7 +386,7 @@ private String getAccessToken(String userName, String clientId) { .param("client_id", "quarkus-app-" + clientId) .param("client_secret", "secret") .when() - .post(KEYCLOAK_SERVER_URL + "/realms/" + KEYCLOAK_REALM + clientId + "/protocol/openid-connect/token") + .post(KEYCLOAK_SERVER_URL + "/realms/" + KEYCLOAK_REALM + realmId + "/protocol/openid-connect/token") .as(AccessTokenResponse.class).getToken(); } diff --git a/integration-tests/oidc-tenancy/src/test/java/io/quarkus/it/keycloak/KeycloakRealmResourceManager.java b/integration-tests/oidc-tenancy/src/test/java/io/quarkus/it/keycloak/KeycloakRealmResourceManager.java index 6cd30e10fafb0..5725ebc832e30 100644 --- a/integration-tests/oidc-tenancy/src/test/java/io/quarkus/it/keycloak/KeycloakRealmResourceManager.java +++ b/integration-tests/oidc-tenancy/src/test/java/io/quarkus/it/keycloak/KeycloakRealmResourceManager.java @@ -30,6 +30,9 @@ public Map start() { RealmRepresentation realm = createRealm(KEYCLOAK_REALM + realmId); realm.getClients().add(createClient("quarkus-app-" + realmId)); + if ("b".equals(realmId)) { + realm.getClients().add(createClient("quarkus-app-b2")); + } realm.getUsers().add(createUser("alice", "user")); realm.getUsers().add(createUser("admin", "user", "admin")); realm.getUsers().add(createUser("jdoe", "user", "confidential")); From 250dc3aacee87d0e2735e3b2a6b282cec5ff2531 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Mathieu?= Date: Fri, 14 May 2021 17:18:18 +0200 Subject: [PATCH 0085/2077] Disable MongoDB IT on windows as they are un-reliable --- .../quarkus/it/mongodb/panache/MongodbPanacheMockingTest.java | 3 +++ .../quarkus/it/mongodb/panache/MongodbPanacheResourceTest.java | 3 +++ .../panache/reactive/ReactiveMongodbPanacheMockingTest.java | 3 +++ .../panache/reactive/ReactiveMongodbPanacheResourceTest.java | 3 +++ .../panache/transaction/MongodbPanacheTransactionTest.java | 3 +++ 5 files changed, 15 insertions(+) diff --git a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongodbPanacheMockingTest.java b/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongodbPanacheMockingTest.java index 0eea1c3d48342..c60e796931612 100644 --- a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongodbPanacheMockingTest.java +++ b/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongodbPanacheMockingTest.java @@ -9,6 +9,8 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledOnOs; +import org.junit.jupiter.api.condition.OS; import org.mockito.Mockito; import io.quarkus.it.mongodb.panache.person.MockablePersonRepository; @@ -23,6 +25,7 @@ @QuarkusTest @QuarkusTestResource(MongoReplicaSetTestResource.class) +@DisabledOnOs(OS.WINDOWS) public class MongodbPanacheMockingTest { @Test diff --git a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongodbPanacheResourceTest.java b/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongodbPanacheResourceTest.java index 5b9abda1c8d92..95a4dabb8601e 100644 --- a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongodbPanacheResourceTest.java +++ b/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongodbPanacheResourceTest.java @@ -14,6 +14,8 @@ import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledOnOs; +import org.junit.jupiter.api.condition.OS; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; @@ -33,6 +35,7 @@ @QuarkusTest @QuarkusTestResource(MongoReplicaSetTestResource.class) +@DisabledOnOs(OS.WINDOWS) class MongodbPanacheResourceTest { private static final TypeRef> LIST_OF_BOOK_TYPE_REF = new TypeRef>() { }; diff --git a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/reactive/ReactiveMongodbPanacheMockingTest.java b/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/reactive/ReactiveMongodbPanacheMockingTest.java index 4ad6cc02023b2..dac1559ba2d0c 100644 --- a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/reactive/ReactiveMongodbPanacheMockingTest.java +++ b/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/reactive/ReactiveMongodbPanacheMockingTest.java @@ -9,6 +9,8 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledOnOs; +import org.junit.jupiter.api.condition.OS; import org.mockito.Mockito; import io.quarkus.it.mongodb.panache.reactive.person.MockableReactivePersonRepository; @@ -22,6 +24,7 @@ @QuarkusTest @QuarkusTestResource(MongoReplicaSetTestResource.class) +@DisabledOnOs(OS.WINDOWS) public class ReactiveMongodbPanacheMockingTest { private static final Duration timeout = Duration.ofSeconds(2); diff --git a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/reactive/ReactiveMongodbPanacheResourceTest.java b/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/reactive/ReactiveMongodbPanacheResourceTest.java index d3b20fcacdab8..cdc80cc28089e 100644 --- a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/reactive/ReactiveMongodbPanacheResourceTest.java +++ b/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/reactive/ReactiveMongodbPanacheResourceTest.java @@ -22,6 +22,8 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledOnOs; +import org.junit.jupiter.api.condition.OS; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; @@ -42,6 +44,7 @@ @QuarkusTest @QuarkusTestResource(MongoReplicaSetTestResource.class) +@DisabledOnOs(OS.WINDOWS) class ReactiveMongodbPanacheResourceTest { private static final TypeRef> LIST_OF_BOOK_TYPE_REF = new TypeRef>() { }; diff --git a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/transaction/MongodbPanacheTransactionTest.java b/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/transaction/MongodbPanacheTransactionTest.java index 12e76f909e873..4b4fa97dd3a72 100644 --- a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/transaction/MongodbPanacheTransactionTest.java +++ b/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/transaction/MongodbPanacheTransactionTest.java @@ -6,6 +6,8 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledOnOs; +import org.junit.jupiter.api.condition.OS; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; @@ -23,6 +25,7 @@ @QuarkusTest @QuarkusTestResource(MongoReplicaSetTestResource.class) +@DisabledOnOs(OS.WINDOWS) class MongodbPanacheTransactionTest { private static final TypeRef> LIST_OF_PERSON_TYPE_REF = new TypeRef>() { }; From 7734c5c6aa6977fa7a527dbb5656bd5def29424d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 May 2021 21:06:51 +0000 Subject: [PATCH 0086/2077] Bump awssdk.version from 2.16.62 to 2.16.63 Bumps `awssdk.version` from 2.16.62 to 2.16.63. Updates `software.amazon.awssdk:bom` from 2.16.62 to 2.16.63 - [Release notes](https://github.com/aws/aws-sdk-java-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-java-v2/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java-v2/compare/2.16.62...2.16.63) Updates `apache-client` from 2.16.62 to 2.16.63 Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index df7a4eacce96e..4133cbd084c0e 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -150,7 +150,7 @@ 3.8.0 1.3.1 2.9.0 - 2.16.62 + 2.16.63 2.38.1 1.4.2 1.4.32 From 342f009ec2e88a73a89edc5ea428191ae7e9e412 Mon Sep 17 00:00:00 2001 From: Felix Seifert Date: Sat, 15 May 2021 10:02:33 +0200 Subject: [PATCH 0087/2077] Fix Minor Errors in Blaze Persistence Guide * Change name of objects in displayed code to correct name * Change order of annotations to ensure consistency --- docs/src/main/asciidoc/blaze-persistence.adoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/src/main/asciidoc/blaze-persistence.adoc b/docs/src/main/asciidoc/blaze-persistence.adoc index f77327baf4e1c..0269f158432aa 100644 --- a/docs/src/main/asciidoc/blaze-persistence.adoc +++ b/docs/src/main/asciidoc/blaze-persistence.adoc @@ -193,12 +193,12 @@ public class GiftResource { @Path("{id}") @Transactional public GiftView updateGift(@EntityViewId("id") GiftUpdateView view) { - evm.save(em, view); - return evm.find(em, GiftView.class, view.getId()); + entityViewManager.save(entityManager, view); + return entityViewManager.find(entityManager, GiftView.class, view.getId()); } - @Path("{id"}) @GET + @Path("{id"}) @Produces(MediaType.APPLICATION_JSON) public GiftView getGift(@PathParam("id") Long id) { return return entityViewManager.find(entityManager, GiftView.class, view.getId()); From bf245388a5f25f73c85a868f2dfdc57439de0c65 Mon Sep 17 00:00:00 2001 From: Alexey Loubyansky Date: Sat, 15 May 2021 23:04:15 +0200 Subject: [PATCH 0088/2077] Base codestarts: declare mavenCentral() before mavenLocal() --- .../buildtool/gradle-kotlin-dsl/base/build-layout.include.qute | 2 +- .../quarkus/buildtool/gradle/base/build-layout.include.qute | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/buildtool/gradle-kotlin-dsl/base/build-layout.include.qute b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/buildtool/gradle-kotlin-dsl/base/build-layout.include.qute index 8fcd7516eba57..942a94c159849 100644 --- a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/buildtool/gradle-kotlin-dsl/base/build-layout.include.qute +++ b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/buildtool/gradle-kotlin-dsl/base/build-layout.include.qute @@ -6,8 +6,8 @@ plugins { {#insert repositories} repositories { - mavenLocal() mavenCentral() + mavenLocal() {#if gradle.repositories} {#for rep in gradle.repositories} maven { url = uri("{rep.url}") } diff --git a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/buildtool/gradle/base/build-layout.include.qute b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/buildtool/gradle/base/build-layout.include.qute index 2331838993019..85150c1e563c3 100644 --- a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/buildtool/gradle/base/build-layout.include.qute +++ b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/buildtool/gradle/base/build-layout.include.qute @@ -6,8 +6,8 @@ plugins { {#insert repositories} repositories { - mavenLocal() mavenCentral() + mavenLocal() {#if gradle.repositories} {#for rep in gradle.repositories} maven { url "{rep.url}" } From a7344760502d9b5ed40b98450056a44db66dbc0d Mon Sep 17 00:00:00 2001 From: Felix Seifert Date: Sun, 16 May 2021 14:49:16 +0200 Subject: [PATCH 0089/2077] Add Information on How to Assign Properties ar Startup * Elaborate slightly on `-D` flag in Config Reference Guide * Complete list about system properties with Quarkus dev mode * Capitalise starts of bullet points * Add information on how to assign command line arguments to Lifecylce Guide --- docs/src/main/asciidoc/config-reference.adoc | 12 ++++++++---- docs/src/main/asciidoc/lifecycle.adoc | 7 ++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/docs/src/main/asciidoc/config-reference.adoc b/docs/src/main/asciidoc/config-reference.adoc index 377ad403d74a9..91643f8aa7375 100644 --- a/docs/src/main/asciidoc/config-reference.adoc +++ b/docs/src/main/asciidoc/config-reference.adoc @@ -46,14 +46,18 @@ image::config-sources.png[] [[system-properties]] === System properties -* for a runner jar: `java -Dquarkus.datasource.password=youshallnotpass -jar target/quarkus-app/quarkus-run.jar` -* for a native executable: `./target/myapp-runner -Dquarkus.datasource.password=youshallnotpass` +System properties can be handed to the application through the `-D` flag during startup. The following examples assign +the value `youshallnotpass` to the attribute `quarkus.datasource.password`. + +* For Quarkus dev mode: `./mvnw quarkus:dev -Dquarkus.datasource.password=youshallnotpass` +* For a runner jar: `java -Dquarkus.datasource.password=youshallnotpass -jar target/quarkus-app/quarkus-run.jar` +* For a native executable: `./target/myapp-runner -Dquarkus.datasource.password=youshallnotpass` [[environment-variables]] === Environment variables -* for a runner jar: `export QUARKUS_DATASOURCE_PASSWORD=youshallnotpass ; java -jar target/quarkus-app/quarkus-run.jar` -* for a native executable: `export QUARKUS_DATASOURCE_PASSWORD=youshallnotpass ; ./target/myapp-runner` +* For a runner jar: `export QUARKUS_DATASOURCE_PASSWORD=youshallnotpass ; java -jar target/quarkus-app/quarkus-run.jar` +* For a native executable: `export QUARKUS_DATASOURCE_PASSWORD=youshallnotpass ; ./target/myapp-runner` NOTE: Environment variables names follow the conversion rules specified by link:https://github.com/eclipse/microprofile-config/blob/master/spec/src/main/asciidoc/configsources.asciidoc#default-configsources[MicroProfile Config]. diff --git a/docs/src/main/asciidoc/lifecycle.adoc b/docs/src/main/asciidoc/lifecycle.adoc index ff24b90f783f4..a5dd6b2c71b3a 100644 --- a/docs/src/main/asciidoc/lifecycle.adoc +++ b/docs/src/main/asciidoc/lifecycle.adoc @@ -62,7 +62,7 @@ By default Quarkus will automatically generate a main method, that will bootstra shutdown to be initiated. Let's provide our own main method: [source,java] ---- -package om.acme; +package com.acme; import io.quarkus.runtime.annotations.QuarkusMain; import io.quarkus.runtime.Quarkus; @@ -133,6 +133,11 @@ It is possible to inject the arguments that were passed in on the command line: String[] args; ---- +Command line arguments can be passed to the application through the `-D` flag with the property `quarkus.args`: + +* For Quarkus dev mode: `./mvnw quarkus:dev -Dquarkus.args=` +* For a runner jar: `java -Dquarkus.args= -jar target/quarkus-app/quarkus-run.jar` +* For a native executable: `./target/lifecycle-quickstart-1.0-SNAPSHOT-runner -Dquarkus.args=` == Listening for startup and shutdown events From 0801cc9c4b5f92cccc5e309377728068eff25e2f Mon Sep 17 00:00:00 2001 From: Falko Modler Date: Sun, 16 May 2021 23:04:05 +0200 Subject: [PATCH 0090/2077] Remove jcenter plugin repos from *-panache-kotlin --- .../panache/hibernate-orm-panache-kotlin/runtime/pom.xml | 8 -------- extensions/panache/mongodb-panache-kotlin/runtime/pom.xml | 8 -------- 2 files changed, 16 deletions(-) diff --git a/extensions/panache/hibernate-orm-panache-kotlin/runtime/pom.xml b/extensions/panache/hibernate-orm-panache-kotlin/runtime/pom.xml index 5b2daa6b0de2d..1bbff593b84d7 100644 --- a/extensions/panache/hibernate-orm-panache-kotlin/runtime/pom.xml +++ b/extensions/panache/hibernate-orm-panache-kotlin/runtime/pom.xml @@ -71,14 +71,6 @@
- - - jcenter - JCenter - https://jcenter.bintray.com/ - - - diff --git a/extensions/panache/mongodb-panache-kotlin/runtime/pom.xml b/extensions/panache/mongodb-panache-kotlin/runtime/pom.xml index bc09fddf5aea8..3d25c5fd5efa6 100644 --- a/extensions/panache/mongodb-panache-kotlin/runtime/pom.xml +++ b/extensions/panache/mongodb-panache-kotlin/runtime/pom.xml @@ -81,14 +81,6 @@
- - - jcenter - JCenter - https://jcenter.bintray.com/ - - - From 995915fac93b8e94792be644a7582d39a3d97ddb Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Mon, 17 May 2021 14:01:02 +1000 Subject: [PATCH 0091/2077] Activate Coroutine request scope --- .../server/runtime/kotlin/ApplicationCoroutineScope.kt | 10 ++++++++-- .../runtime/kotlin/CoroutineInvocationHandler.kt | 4 ++-- .../common/core/AbstractResteasyReactiveContext.java | 8 ++++++++ .../reactive/kotlin/ReactiveGreetingResource.kt | 7 ++++++- .../reactive/kotlin/RequestScopedKotlinClass.kt | 10 ++++++++++ 5 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/RequestScopedKotlinClass.kt diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/kotlin/src/main/kotlin/org/jboss/resteasy/reactive/server/runtime/kotlin/ApplicationCoroutineScope.kt b/extensions/resteasy-reactive/quarkus-resteasy-reactive/kotlin/src/main/kotlin/org/jboss/resteasy/reactive/server/runtime/kotlin/ApplicationCoroutineScope.kt index 0f19949e754fa..ff07849ae1c1a 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/kotlin/src/main/kotlin/org/jboss/resteasy/reactive/server/runtime/kotlin/ApplicationCoroutineScope.kt +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/kotlin/src/main/kotlin/org/jboss/resteasy/reactive/server/runtime/kotlin/ApplicationCoroutineScope.kt @@ -2,6 +2,7 @@ package org.jboss.resteasy.reactive.server.runtime.kotlin import io.vertx.core.Context import kotlinx.coroutines.* +import org.jboss.resteasy.reactive.spi.ThreadSetupAction import javax.annotation.PreDestroy import javax.inject.Singleton import kotlin.coroutines.CoroutineContext @@ -26,11 +27,16 @@ class ApplicationCoroutineScope : CoroutineScope, AutoCloseable { /** * Dispatches the coroutine in Vertx IO thread. */ -class VertxDispatcher(private val vertxContext: Context) : CoroutineDispatcher() { +class VertxDispatcher(private val vertxContext: Context, private val requestScope : ThreadSetupAction.ThreadState) : CoroutineDispatcher() { override fun dispatch(context: CoroutineContext, block: Runnable) { // context propagation for suspending functions is not enabled yet, will be handled later vertxContext.runOnContext { - block.run() + requestScope.activate() + try { + block.run() + } finally { + requestScope.deactivate() + } } } } diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/kotlin/src/main/kotlin/org/jboss/resteasy/reactive/server/runtime/kotlin/CoroutineInvocationHandler.kt b/extensions/resteasy-reactive/quarkus-resteasy-reactive/kotlin/src/main/kotlin/org/jboss/resteasy/reactive/server/runtime/kotlin/CoroutineInvocationHandler.kt index 9d908913f85dd..b68f2dde588c6 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/kotlin/src/main/kotlin/org/jboss/resteasy/reactive/server/runtime/kotlin/CoroutineInvocationHandler.kt +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/kotlin/src/main/kotlin/org/jboss/resteasy/reactive/server/runtime/kotlin/CoroutineInvocationHandler.kt @@ -24,12 +24,12 @@ class CoroutineInvocationHandler(private val invoker: EndpointInvoker, return } - val dispatcher: CoroutineDispatcher = Vertx.currentContext()?.let(::VertxDispatcher) + val requestScope = requestContext.captureCDIRequestScope() + val dispatcher: CoroutineDispatcher = Vertx.currentContext()?.let {VertxDispatcher(it,requestScope)} ?: throw IllegalStateException("No Vertx context found") logger.trace("Handling request with dispatcher {}", dispatcher) - requestContext.requireCDIRequestScope() requestContext.suspend() coroutineScope.launch(context = dispatcher) { try { diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/core/AbstractResteasyReactiveContext.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/core/AbstractResteasyReactiveContext.java index 82d8ac45a48df..d35a3b7fba628 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/core/AbstractResteasyReactiveContext.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/core/AbstractResteasyReactiveContext.java @@ -221,6 +221,14 @@ public void requireCDIRequestScope() { handleRequestScopeActivation(); } + /** + * Captures the CDI request scope for use outside of handler chains. + */ + public ThreadSetupAction.ThreadState captureCDIRequestScope() { + requireCDIRequestScope(); + return currentRequestScope; + } + protected abstract void handleRequestScopeActivation(); /** diff --git a/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/ReactiveGreetingResource.kt b/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/ReactiveGreetingResource.kt index c395766203428..59399699d5762 100644 --- a/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/ReactiveGreetingResource.kt +++ b/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/ReactiveGreetingResource.kt @@ -4,18 +4,23 @@ import kotlinx.coroutines.delay import java.io.BufferedReader import java.io.InputStreamReader import java.net.URL +import javax.inject.Inject import javax.ws.rs.GET import javax.ws.rs.Path import javax.ws.rs.Produces import javax.ws.rs.core.MediaType @Path("/hello-resteasy-reactive") -class ReactiveGreetingResource { +class ReactiveGreetingResource @Inject constructor (val req : RequestScopedKotlinClass){ @GET @Produces(MediaType.TEXT_PLAIN) suspend fun hello(): String { + req.message = "msg" delay(50) doSomeWork() + if (req.message != "msg") { + throw Throwable("Request scoped data was lost"); + } return "Hello RestEASY Reactive" } diff --git a/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/RequestScopedKotlinClass.kt b/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/RequestScopedKotlinClass.kt new file mode 100644 index 0000000000000..8349754e3d726 --- /dev/null +++ b/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/RequestScopedKotlinClass.kt @@ -0,0 +1,10 @@ +package io.quarkus.it.resteasy.reactive.kotlin + +import javax.enterprise.context.RequestScoped + +@RequestScoped +class RequestScopedKotlinClass { + + var message : String = "initial"; + +} \ No newline at end of file From f230fa90d157e486470d82a372d4f4699463dfef Mon Sep 17 00:00:00 2001 From: Clement Escoffier Date: Sun, 16 May 2021 19:57:01 +0200 Subject: [PATCH 0092/2077] Update Vert.x to version 4.1.0.Beta1 Also fix the SSLHelper substitution. --- bom/application/pom.xml | 2 +- .../vertx/core/runtime/graal/VertxSubstitutions.java | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index df7a4eacce96e..40d2832172f22 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -113,7 +113,7 @@ 1.15.3.Final 1.8.7.Final 3.2.0.Final - 4.0.3 + 4.1.0.Beta1 4.5.13 4.4.14 4.1.4 diff --git a/extensions/vertx-core/runtime/src/main/java/io/quarkus/vertx/core/runtime/graal/VertxSubstitutions.java b/extensions/vertx-core/runtime/src/main/java/io/quarkus/vertx/core/runtime/graal/VertxSubstitutions.java index af479bf38d06f..cf3bd45ce733a 100644 --- a/extensions/vertx-core/runtime/src/main/java/io/quarkus/vertx/core/runtime/graal/VertxSubstitutions.java +++ b/extensions/vertx-core/runtime/src/main/java/io/quarkus/vertx/core/runtime/graal/VertxSubstitutions.java @@ -152,9 +152,6 @@ final class Target_io_vertx_core_net_impl_SSLHelper { @Alias private boolean openSsl; - @Alias - private boolean useAlpn; - @Alias private List applicationProtocols; @@ -164,7 +161,8 @@ private KeyManagerFactory getKeyMgrFactory(VertxInternal vertx) throws Exception } @Substitute - private SslContext createContext(VertxInternal vertx, X509KeyManager mgr, TrustManagerFactory trustMgrFactory) { + private SslContext createContext(VertxInternal vertx, boolean useAlpn, X509KeyManager mgr, + TrustManagerFactory trustMgrFactory) { try { SslContextBuilder builder; if (client) { From 20564322ddf4d98112ef3a4122030ed6e99e139c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Mathieu?= Date: Mon, 17 May 2021 10:19:04 +0200 Subject: [PATCH 0093/2077] Disable mongodb-client IT in windows as they are unreliable --- .../src/test/java/io/quarkus/it/mongodb/BookResourceTest.java | 3 +++ .../it/mongodb/BookResourceWithParameterInjectionTest.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/integration-tests/mongodb-client/src/test/java/io/quarkus/it/mongodb/BookResourceTest.java b/integration-tests/mongodb-client/src/test/java/io/quarkus/it/mongodb/BookResourceTest.java index b5bbc1750853a..d879630e816a3 100644 --- a/integration-tests/mongodb-client/src/test/java/io/quarkus/it/mongodb/BookResourceTest.java +++ b/integration-tests/mongodb-client/src/test/java/io/quarkus/it/mongodb/BookResourceTest.java @@ -9,6 +9,8 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledOnOs; +import org.junit.jupiter.api.condition.OS; import io.quarkus.mongodb.health.MongoHealthCheck; import io.quarkus.test.common.QuarkusTestResource; @@ -18,6 +20,7 @@ @QuarkusTest @QuarkusTestResource(MongoTestResource.class) +@DisabledOnOs(OS.WINDOWS) public class BookResourceTest { private static Jsonb jsonb; diff --git a/integration-tests/mongodb-client/src/test/java/io/quarkus/it/mongodb/BookResourceWithParameterInjectionTest.java b/integration-tests/mongodb-client/src/test/java/io/quarkus/it/mongodb/BookResourceWithParameterInjectionTest.java index 3dce47f6694c2..ad3d182e6e8ba 100644 --- a/integration-tests/mongodb-client/src/test/java/io/quarkus/it/mongodb/BookResourceWithParameterInjectionTest.java +++ b/integration-tests/mongodb-client/src/test/java/io/quarkus/it/mongodb/BookResourceWithParameterInjectionTest.java @@ -5,6 +5,8 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledOnOs; +import org.junit.jupiter.api.condition.OS; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; @@ -12,6 +14,7 @@ @QuarkusTest @QuarkusTestResource(MongoTestResource.class) +@DisabledOnOs(OS.WINDOWS) public class BookResourceWithParameterInjectionTest { private static Jsonb jsonb; From d15748f9a94445889ea28b8d2787177f5b365b3e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 May 2021 10:06:57 +0000 Subject: [PATCH 0094/2077] Bump junit-jupiter from 5.7.1 to 5.7.2 Bumps [junit-jupiter](https://github.com/junit-team/junit5) from 5.7.1 to 5.7.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.7.1...r5.7.2) Signed-off-by: dependabot[bot] --- independent-projects/tools/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/independent-projects/tools/pom.xml b/independent-projects/tools/pom.xml index 9f7c397862d9e..0665d47e98e13 100644 --- a/independent-projects/tools/pom.xml +++ b/independent-projects/tools/pom.xml @@ -44,7 +44,7 @@ 2.0.2 4.0.3 1.1.2 - 5.7.1 + 5.7.2 1.20 3.4.1.Final 3.8.1 From a9d9a69c59791ac74e77cbcc39f5769723c40a93 Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Fri, 7 May 2021 01:21:13 +0100 Subject: [PATCH 0095/2077] Update SmallRye Config to 2.3.0. --- bom/application/pom.xml | 7 +- .../deployment/steps/ConfigBuildSteps.java | 4 +- ...plicationPropertiesConfigSourceLoader.java | 21 ++-- .../runtime/configuration/ConfigUtils.java | 13 ++- .../arc/deployment/ConfigBuildStep.java | 108 +++++++++++++----- .../arc/deployment/ConfigClassBuildItem.java | 53 +++++++++ .../deployment/ConfigMappingBuildItem.java | 21 ---- .../io/quarkus/arc/config/ConfigIgnore.java | 4 + .../io/quarkus/arc/config/ConfigPrefix.java | 4 + .../quarkus/arc/config/ConfigProperties.java | 4 + .../quarkus/arc/runtime/ConfigRecorder.java | 14 ++- .../ApplicationYamlConfigSourceLoader.java | 23 +--- .../HibernateValidatorProcessor.java | 8 ++ .../config/ConfigMappingValidatorTest.java | 41 +++++++ .../hibernate-validator/runtime/pom.xml | 4 + ...ibernateBeanValidationConfigValidator.java | 12 ++ .../io.smallrye.config.ConfigValidator | 2 + integration-tests/smallrye-config/pom.xml | 17 +++ .../io/quarkus/it/smallrye/config/Cloud.java | 10 ++ .../io/quarkus/it/smallrye/config/Server.java | 42 ++++++- .../it/smallrye/config/ServerResource.java | 29 +++++ .../src/main/resources/application.yaml | 43 +++++++ .../smallrye/config/ServerResourceTest.java | 33 ++++++ tcks/microprofile-config/pom.xml | 1 - 24 files changed, 425 insertions(+), 93 deletions(-) create mode 100644 extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigClassBuildItem.java delete mode 100644 extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigMappingBuildItem.java create mode 100644 extensions/hibernate-validator/deployment/src/test/java/io/quarkus/hibernate/validator/test/config/ConfigMappingValidatorTest.java create mode 100644 extensions/hibernate-validator/runtime/src/main/java/io/quarkus/hibernate/validator/runtime/HibernateBeanValidationConfigValidator.java create mode 100644 extensions/hibernate-validator/runtime/src/main/resources/META-INF/services/io.smallrye.config.ConfigValidator create mode 100644 integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Cloud.java diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 4133cbd084c0e..322e97492a392 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -42,7 +42,7 @@ 2.0 1.2 1.6.0 - 2.2.0 + 2.3.0 3.0.2 3.0.1 2.1.4 @@ -3179,6 +3179,11 @@ smallrye-config-common ${smallrye-config.version}
+ + io.smallrye.config + smallrye-config-validator + ${smallrye-config.version} + io.smallrye.config smallrye-config-source-yaml diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigBuildSteps.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigBuildSteps.java index 0699b8d2d6d95..1019d415ea756 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigBuildSteps.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigBuildSteps.java @@ -30,6 +30,7 @@ import io.smallrye.config.ConfigSourceFactory; import io.smallrye.config.ConfigSourceInterceptor; import io.smallrye.config.ConfigSourceInterceptorFactory; +import io.smallrye.config.ConfigValidator; import io.smallrye.config.SmallRyeConfigProviderResolver; class ConfigBuildSteps { @@ -88,7 +89,8 @@ void nativeServiceProviders( Converter.class, ConfigSourceInterceptor.class, ConfigSourceInterceptorFactory.class, - ConfigSourceFactory.class)) { + ConfigSourceFactory.class, + ConfigValidator.class)) { final String serviceName = serviceClass.getName(); final Set names = ServiceUtil.classNamesNamedIn(classLoader, SERVICES_PREFIX + serviceName); final List list = names.stream() diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ApplicationPropertiesConfigSourceLoader.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ApplicationPropertiesConfigSourceLoader.java index f5ac2de74bf0a..2aba6e8589a61 100644 --- a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ApplicationPropertiesConfigSourceLoader.java +++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ApplicationPropertiesConfigSourceLoader.java @@ -3,6 +3,7 @@ import java.io.IOException; import java.net.URI; import java.net.URL; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; @@ -24,35 +25,27 @@ protected ConfigSource loadConfigSource(final URL url, final int ordinal) throws } public static class InClassPath extends ApplicationPropertiesConfigSourceLoader implements ConfigSourceProvider { - @Override - protected ConfigSource loadConfigSource(final URL url, final int ordinal) throws IOException { - return super.loadConfigSource(url, 250); - } - @Override public List getConfigSources(final ClassLoader classLoader) { - return loadConfigSources("application.properties", classLoader); + return loadConfigSources("application.properties", 250, classLoader); } @Override - protected List tryFileSystem(final URI uri) { + protected List tryFileSystem(final URI uri, final int ordinal) { return new ArrayList<>(); } } public static class InFileSystem extends ApplicationPropertiesConfigSourceLoader implements ConfigSourceProvider { - @Override - protected ConfigSource loadConfigSource(final URL url, final int ordinal) throws IOException { - return super.loadConfigSource(url, 260); - } - @Override public List getConfigSources(final ClassLoader classLoader) { - return loadConfigSources("config/application.properties", classLoader); + return loadConfigSources( + Paths.get(System.getProperty("user.dir"), "config", "application.properties").toUri().toString(), 260, + classLoader); } @Override - protected List tryClassPath(final URI uri, final ClassLoader classLoader) { + protected List tryClassPath(final URI uri, final int ordinal, final ClassLoader classLoader) { return new ArrayList<>(); } } diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java index 4c070f03f55b3..1ea1cb9fc8b76 100644 --- a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java +++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java @@ -1,10 +1,10 @@ package io.quarkus.runtime.configuration; -import static io.smallrye.config.AbstractLocationConfigSourceFactory.SMALLRYE_LOCATIONS; import static io.smallrye.config.DotEnvConfigSourceProvider.dotEnvSources; -import static io.smallrye.config.ProfileConfigSourceInterceptor.SMALLRYE_PROFILE; -import static io.smallrye.config.ProfileConfigSourceInterceptor.SMALLRYE_PROFILE_PARENT; import static io.smallrye.config.PropertiesConfigSourceProvider.classPathSources; +import static io.smallrye.config.SmallRyeConfig.SMALLRYE_CONFIG_LOCATIONS; +import static io.smallrye.config.SmallRyeConfig.SMALLRYE_CONFIG_PROFILE; +import static io.smallrye.config.SmallRyeConfig.SMALLRYE_CONFIG_PROFILE_PARENT; import static io.smallrye.config.SmallRyeConfigBuilder.META_INF_MICROPROFILE_CONFIG_PROPERTIES; import java.io.IOException; @@ -116,11 +116,11 @@ public static SmallRyeConfigBuilder configBuilder(final boolean runTime, final b public static SmallRyeConfigBuilder emptyConfigBuilder() { final SmallRyeConfigBuilder builder = new SmallRyeConfigBuilder(); - builder.withDefaultValue(SMALLRYE_PROFILE, ProfileManager.getActiveProfile()); + builder.withDefaultValue(SMALLRYE_CONFIG_PROFILE, ProfileManager.getActiveProfile()); final Map relocations = new HashMap<>(); - relocations.put(SMALLRYE_LOCATIONS, "quarkus.config.locations"); - relocations.put(SMALLRYE_PROFILE_PARENT, "quarkus.config.profile.parent"); + relocations.put(SMALLRYE_CONFIG_LOCATIONS, "quarkus.config.locations"); + relocations.put(SMALLRYE_CONFIG_PROFILE_PARENT, "quarkus.config.profile.parent"); // Override the priority, because of the ProfileConfigSourceInterceptor and profile.parent. builder.withInterceptorFactories(new ConfigSourceInterceptorFactory() { @Override @@ -137,6 +137,7 @@ public OptionalInt getPriority() { builder.addDefaultInterceptors(); builder.addDiscoveredInterceptors(); builder.addDiscoveredConverters(); + builder.addDiscoveredValidator(); return builder; } diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigBuildStep.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigBuildStep.java index 2dd8af0b06964..e9430dcd36652 100644 --- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigBuildStep.java +++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigBuildStep.java @@ -1,9 +1,13 @@ package io.quarkus.arc.deployment; +import static io.quarkus.arc.deployment.ConfigClassBuildItem.Type.MAPPING; +import static io.quarkus.arc.deployment.ConfigClassBuildItem.Type.PROPERTIES; import static io.quarkus.deployment.annotations.ExecutionTime.RUNTIME_INIT; -import static io.smallrye.config.ConfigMappings.ConfigMappingWithPrefix.configMappingWithPrefix; +import static io.smallrye.config.ConfigMappings.ConfigClassWithPrefix.configClassWithPrefix; +import static java.util.Collections.emptySet; import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toSet; +import static org.eclipse.microprofile.config.inject.ConfigProperties.UNCONFIGURED_PREFIX; import static org.jboss.jandex.AnnotationInstance.create; import static org.jboss.jandex.AnnotationTarget.Kind.CLASS; import static org.jboss.jandex.AnnotationTarget.Kind.FIELD; @@ -57,14 +61,13 @@ import io.smallrye.config.ConfigMapping; import io.smallrye.config.ConfigMappingLoader; import io.smallrye.config.ConfigMappingMetadata; -import io.smallrye.config.ConfigMappings.ConfigMappingWithPrefix; +import io.smallrye.config.ConfigMappings.ConfigClassWithPrefix; import io.smallrye.config.inject.ConfigProducer; /** * MicroProfile Config related build steps. */ public class ConfigBuildStep { - private static final DotName MP_CONFIG_PROPERTY_NAME = DotName.createSimple(ConfigProperty.class.getName()); private static final DotName MP_CONFIG_PROPERTIES_NAME = DotName.createSimple(ConfigProperties.class.getName()); private static final DotName MP_CONFIG_VALUE_NAME = DotName.createSimple(ConfigValue.class.getName()); @@ -226,13 +229,11 @@ public void transform(TransformationContext context) { } @BuildStep - void generateConfigMappings( + void generateConfigClasses( CombinedIndexBuildItem combinedIndex, - BeanRegistrationPhaseBuildItem beanRegistrationPhase, BuildProducer generatedClasses, BuildProducer reflectiveClasses, - BuildProducer configMappings, - BuildProducer beanConfigurationRegistry) { + BuildProducer configClasses) { List mappingAnnotations = new ArrayList<>(); mappingAnnotations.addAll(combinedIndex.getIndex().getAnnotations(CONFIG_MAPPING_NAME)); @@ -243,18 +244,20 @@ void generateConfigMappings( AnnotationValue annotationPrefix = instance.value("prefix"); if (target.kind().equals(FIELD)) { - if (annotationPrefix != null && !annotationPrefix.asString().equals(ConfigProperties.UNCONFIGURED_PREFIX)) { - configMappings.produce( - new ConfigMappingBuildItem(toClass(target.asField().type().name()), annotationPrefix.asString())); + if (annotationPrefix != null && !annotationPrefix.asString().equals(UNCONFIGURED_PREFIX)) { + configClasses.produce( + toConfigClassBuildItem(instance, toClass(target.asField().type().name()), + annotationPrefix.asString())); continue; } } if (target.kind().equals(METHOD_PARAMETER)) { - if (annotationPrefix != null && !annotationPrefix.asString().equals(ConfigProperties.UNCONFIGURED_PREFIX)) { + if (annotationPrefix != null && !annotationPrefix.asString().equals(UNCONFIGURED_PREFIX)) { ClassType classType = target.asMethodParameter().method().parameters() .get(target.asMethodParameter().position()).asClassType(); - configMappings.produce(new ConfigMappingBuildItem(toClass(classType.name()), annotationPrefix.asString())); + configClasses + .produce(toConfigClassBuildItem(instance, toClass(classType.name()), annotationPrefix.asString())); continue; } } @@ -263,11 +266,12 @@ void generateConfigMappings( continue; } - Class type = toClass(target.asClass().name()); + Class configClass = toClass(target.asClass().name()); String prefix = Optional.ofNullable(annotationPrefix).map(AnnotationValue::asString).orElse(""); - List configMappingsMetadata = ConfigMappingLoader.getConfigMappingsMetadata(type); - List mappingsInfo = new ArrayList<>(); + List configMappingsMetadata = ConfigMappingLoader.getConfigMappingsMetadata(configClass); + Set generatedClassesNames = new HashSet<>(); + Set mappingsInfo = new HashSet<>(); configMappingsMetadata.forEach(mappingMetadata -> { generatedClasses.produce( new GeneratedClassBuildItem(true, mappingMetadata.getClassName(), mappingMetadata.getClassBytes())); @@ -276,6 +280,8 @@ void generateConfigMappings( reflectiveClasses .produce(ReflectiveClassBuildItem.builder(mappingMetadata.getClassName()).constructors(true).build()); + generatedClassesNames.add(mappingMetadata.getClassName()); + ClassInfo mappingInfo = combinedIndex.getIndex() .getClassByName(DotName.createSimple(mappingMetadata.getInterfaceType().getName())); if (mappingInfo != null) { @@ -296,40 +302,63 @@ void generateConfigMappings( } } - configMappings.produce(new ConfigMappingBuildItem(type, prefix)); + configClasses.produce(toConfigClassBuildItem(instance, configClass, generatedClassesNames, prefix)); + } + } + + @BuildStep + void beanConfigClasses( + List configClasses, + BeanRegistrationPhaseBuildItem beanRegistrationPhase, + BuildProducer beanConfigurationRegistry) { + + for (ConfigClassBuildItem configClass : configClasses) { + if (configClass.getGeneratedClasses().isEmpty()) { + continue; + } List qualifiers = new ArrayList<>(); - if (instance.name().equals(MP_CONFIG_PROPERTIES_NAME)) { + if (configClass.isProperties()) { qualifiers.add( - create(MP_CONFIG_PROPERTIES_NAME, null, new AnnotationValue[] { createStringValue("prefix", prefix) })); + create(MP_CONFIG_PROPERTIES_NAME, null, + new AnnotationValue[] { createStringValue("prefix", configClass.getPrefix()) })); } beanConfigurationRegistry.produce(new BeanConfiguratorBuildItem( beanRegistrationPhase.getContext() - .configure(type) - .types(type) + .configure(configClass.getConfigClass()) + .types(configClass.getConfigClass()) .qualifiers(qualifiers.toArray(new AnnotationInstance[] {})) .creator(ConfigMappingCreator.class) - .param("type", type) - .param("prefix", prefix))); + .param("type", configClass.getConfigClass()) + .param("prefix", configClass.getPrefix()))); } } @BuildStep @Record(RUNTIME_INIT) - void registerConfigMappings( + void registerConfigClasses( RecorderContext context, ConfigRecorder recorder, - List configMappings) throws Exception { + List configClasses) throws Exception { context.registerNonDefaultConstructor( - ConfigMappingWithPrefix.class.getDeclaredConstructor(Class.class, String.class), - configMappingWithPrefix -> Stream.of(configMappingWithPrefix.getKlass(), configMappingWithPrefix.getPrefix()) + ConfigClassWithPrefix.class.getDeclaredConstructor(Class.class, String.class), + configClassWithPrefix -> Stream.of(configClassWithPrefix.getKlass(), configClassWithPrefix.getPrefix()) .collect(toList())); - recorder.registerConfigMappings(configMappings.stream() - .map(configMapping -> configMappingWithPrefix(configMapping.getInterfaceType(), configMapping.getPrefix())) - .collect(toSet())); + recorder.registerConfigMappings( + configClasses.stream() + .filter(ConfigClassBuildItem::isMapping) + .map(configMapping -> configClassWithPrefix(configMapping.getConfigClass(), configMapping.getPrefix())) + .collect(toSet())); + + recorder.registerConfigProperties( + configClasses.stream() + .filter(ConfigClassBuildItem::isProperties) + .map(configProperties -> configClassWithPrefix(configProperties.getConfigClass(), + configProperties.getPrefix())) + .collect(toSet())); } private static Class toClass(DotName dotName) { @@ -341,6 +370,27 @@ private static Class toClass(DotName dotName) { } } + private static ConfigClassBuildItem toConfigClassBuildItem( + AnnotationInstance instance, + Class configClass, + String prefix) { + return toConfigClassBuildItem(instance, configClass, emptySet(), prefix); + } + + private static ConfigClassBuildItem toConfigClassBuildItem( + AnnotationInstance instance, + Class configClass, + Set generatedClasses, + String prefix) { + if (instance.name().equals(CONFIG_MAPPING_NAME)) { + return new ConfigClassBuildItem(configClass, generatedClasses, prefix, MAPPING); + } else if (instance.name().equals(MP_CONFIG_PROPERTIES_NAME)) { + return new ConfigClassBuildItem(configClass, generatedClasses, prefix, PROPERTIES); + } else { + throw new IllegalArgumentException(); + } + } + private String getPropertyName(String name, ClassInfo declaringClass) { StringBuilder builder = new StringBuilder(); if (declaringClass.enclosingClass() == null) { diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigClassBuildItem.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigClassBuildItem.java new file mode 100644 index 0000000000000..1d011ddbe5824 --- /dev/null +++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigClassBuildItem.java @@ -0,0 +1,53 @@ +package io.quarkus.arc.deployment; + +import java.util.Set; + +import io.quarkus.builder.item.MultiBuildItem; + +public final class ConfigClassBuildItem extends MultiBuildItem { + private final Class configClass; + private final Set generatedClasses; + private final String prefix; + private final Type type; + + public ConfigClassBuildItem( + final Class configClass, + final Set generatedClasses, + final String prefix, + final Type type) { + + this.configClass = configClass; + this.generatedClasses = generatedClasses; + this.prefix = prefix; + this.type = type; + } + + public Class getConfigClass() { + return configClass; + } + + public Set getGeneratedClasses() { + return generatedClasses; + } + + public String getPrefix() { + return prefix; + } + + public Type getType() { + return type; + } + + public boolean isMapping() { + return Type.MAPPING.equals(type); + } + + public boolean isProperties() { + return Type.PROPERTIES.equals(type); + } + + public enum Type { + MAPPING, + PROPERTIES; + } +} diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigMappingBuildItem.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigMappingBuildItem.java deleted file mode 100644 index b97fa357e77e9..0000000000000 --- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigMappingBuildItem.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.quarkus.arc.deployment; - -import io.quarkus.builder.item.MultiBuildItem; - -public final class ConfigMappingBuildItem extends MultiBuildItem { - private final Class interfaceType; - private final String prefix; - - public ConfigMappingBuildItem(final Class interfaceType, final String prefix) { - this.interfaceType = interfaceType; - this.prefix = prefix; - } - - public Class getInterfaceType() { - return interfaceType; - } - - public String getPrefix() { - return prefix; - } -} diff --git a/extensions/arc/runtime/src/main/java/io/quarkus/arc/config/ConfigIgnore.java b/extensions/arc/runtime/src/main/java/io/quarkus/arc/config/ConfigIgnore.java index b73a65fdf5424..ff11ee45db049 100644 --- a/extensions/arc/runtime/src/main/java/io/quarkus/arc/config/ConfigIgnore.java +++ b/extensions/arc/runtime/src/main/java/io/quarkus/arc/config/ConfigIgnore.java @@ -9,7 +9,11 @@ /** * When applied to a field of class annotated with {@link ConfigProperties}, that field will be ignored * for the purposes of configuration + * + * @deprecated Please, use {@link io.smallrye.config.ConfigMapping} instead. This will be removed in a future Quarkus + * version. */ +@Deprecated @Target(FIELD) @Retention(RUNTIME) public @interface ConfigIgnore { diff --git a/extensions/arc/runtime/src/main/java/io/quarkus/arc/config/ConfigPrefix.java b/extensions/arc/runtime/src/main/java/io/quarkus/arc/config/ConfigPrefix.java index 6a0ccf5d7510a..a24b68e28f51c 100644 --- a/extensions/arc/runtime/src/main/java/io/quarkus/arc/config/ConfigPrefix.java +++ b/extensions/arc/runtime/src/main/java/io/quarkus/arc/config/ConfigPrefix.java @@ -11,7 +11,11 @@ /** * Uses in order to set the prefix for a configuration object at the injection point + * + * @deprecated Please, use {@link io.smallrye.config.ConfigMapping} instead. This will be removed in a future Quarkus + * version. */ +@Deprecated @Qualifier @Target({ FIELD, PARAMETER }) @Retention(RUNTIME) diff --git a/extensions/arc/runtime/src/main/java/io/quarkus/arc/config/ConfigProperties.java b/extensions/arc/runtime/src/main/java/io/quarkus/arc/config/ConfigProperties.java index 6df0fcc1e725a..f7fb0886c8013 100644 --- a/extensions/arc/runtime/src/main/java/io/quarkus/arc/config/ConfigProperties.java +++ b/extensions/arc/runtime/src/main/java/io/quarkus/arc/config/ConfigProperties.java @@ -10,7 +10,11 @@ /** * Allow configuration properties with a common prefix to be grouped into a single class + * + * @deprecated Please, use {@link io.smallrye.config.ConfigMapping} instead. This will be removed in a future Quarkus + * version. */ +@Deprecated @Target({ TYPE }) @Retention(RUNTIME) public @interface ConfigProperties { diff --git a/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/ConfigRecorder.java b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/ConfigRecorder.java index 68350c3b60d3f..c232571d6c513 100644 --- a/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/ConfigRecorder.java +++ b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/ConfigRecorder.java @@ -10,6 +10,7 @@ import io.quarkus.runtime.annotations.Recorder; import io.smallrye.config.ConfigMappings; +import io.smallrye.config.ConfigMappings.ConfigClassWithPrefix; import io.smallrye.config.ConfigValidationException; import io.smallrye.config.SmallRyeConfig; import io.smallrye.config.inject.ConfigProducerUtil; @@ -43,10 +44,19 @@ public void validateConfigProperties(Set properties) { } } - public void registerConfigMappings(final Set configMappingsWithPrefix) { + public void registerConfigMappings(final Set configClasses) { try { SmallRyeConfig config = (SmallRyeConfig) ConfigProvider.getConfig(); - ConfigMappings.registerConfigMappings(config, configMappingsWithPrefix); + ConfigMappings.registerConfigMappings(config, configClasses); + } catch (ConfigValidationException e) { + throw new DeploymentException(e.getMessage(), e); + } + } + + public void registerConfigProperties(final Set configClasses) { + try { + SmallRyeConfig config = (SmallRyeConfig) ConfigProvider.getConfig(); + ConfigMappings.registerConfigProperties(config, configClasses); } catch (ConfigValidationException e) { throw new DeploymentException(e.getMessage(), e); } diff --git a/extensions/config-yaml/runtime/src/main/java/io/quarkus/config/yaml/runtime/ApplicationYamlConfigSourceLoader.java b/extensions/config-yaml/runtime/src/main/java/io/quarkus/config/yaml/runtime/ApplicationYamlConfigSourceLoader.java index cfb664721c4b6..2f063642c30b9 100644 --- a/extensions/config-yaml/runtime/src/main/java/io/quarkus/config/yaml/runtime/ApplicationYamlConfigSourceLoader.java +++ b/extensions/config-yaml/runtime/src/main/java/io/quarkus/config/yaml/runtime/ApplicationYamlConfigSourceLoader.java @@ -19,7 +19,6 @@ protected String[] getFileExtensions() { "yaml", "yml" }; - } @Override @@ -28,41 +27,31 @@ protected ConfigSource loadConfigSource(final URL url, final int ordinal) throws } public static class InClassPath extends ApplicationYamlConfigSourceLoader implements ConfigSourceProvider { - @Override - protected ConfigSource loadConfigSource(final URL url, final int ordinal) throws IOException { - return super.loadConfigSource(url, 255); - } - @Override public List getConfigSources(final ClassLoader classLoader) { List configSources = new ArrayList<>(); - configSources.addAll(loadConfigSources("application.yaml", classLoader)); - configSources.addAll(loadConfigSources("application.yml", classLoader)); + configSources.addAll(loadConfigSources("application.yaml", 255, classLoader)); + configSources.addAll(loadConfigSources("application.yml", 255, classLoader)); return configSources; } @Override - protected List tryFileSystem(final URI uri) { + protected List tryFileSystem(final URI uri, final int ordinal) { return new ArrayList<>(); } } public static class InFileSystem extends ApplicationYamlConfigSourceLoader implements ConfigSourceProvider { - @Override - protected ConfigSource loadConfigSource(final URL url, final int ordinal) throws IOException { - return super.loadConfigSource(url, 265); - } - @Override public List getConfigSources(final ClassLoader classLoader) { List configSources = new ArrayList<>(); - configSources.addAll(loadConfigSources("config/application.yaml", classLoader)); - configSources.addAll(loadConfigSources("config/application.yml", classLoader)); + configSources.addAll(loadConfigSources("config/application.yaml", 265, classLoader)); + configSources.addAll(loadConfigSources("config/application.yml", 265, classLoader)); return configSources; } @Override - protected List tryClassPath(final URI uri, final ClassLoader classLoader) { + protected List tryClassPath(final URI uri, final int ordinal, final ClassLoader classLoader) { return new ArrayList<>(); } } diff --git a/extensions/hibernate-validator/deployment/src/main/java/io/quarkus/hibernate/validator/deployment/HibernateValidatorProcessor.java b/extensions/hibernate-validator/deployment/src/main/java/io/quarkus/hibernate/validator/deployment/HibernateValidatorProcessor.java index 2eb14a165ce05..8aa4bdcfefe1c 100644 --- a/extensions/hibernate-validator/deployment/src/main/java/io/quarkus/hibernate/validator/deployment/HibernateValidatorProcessor.java +++ b/extensions/hibernate-validator/deployment/src/main/java/io/quarkus/hibernate/validator/deployment/HibernateValidatorProcessor.java @@ -48,6 +48,7 @@ import io.quarkus.arc.deployment.AutoAddScopeBuildItem; import io.quarkus.arc.deployment.BeanArchiveIndexBuildItem; import io.quarkus.arc.deployment.BeanContainerListenerBuildItem; +import io.quarkus.arc.deployment.ConfigClassBuildItem; import io.quarkus.arc.deployment.SyntheticBeanBuildItem; import io.quarkus.arc.deployment.UnremovableBeanBuildItem; import io.quarkus.arc.processor.BeanInfo; @@ -182,6 +183,7 @@ public void build(HibernateValidatorRecorder recorder, RecorderContext recorderC BuildProducer beanContainerListener, BuildProducer beanValidationAnnotations, ShutdownContextBuildItem shutdownContext, + List configClasses, List additionalJaxRsResourceMethodAnnotations, Capabilities capabilities, LocalesBuildTimeConfig localesBuildTimeConfig, @@ -274,6 +276,12 @@ public void build(HibernateValidatorRecorder recorder, RecorderContext recorderC } } + for (ConfigClassBuildItem configClass : configClasses) { + for (String generatedClass : configClass.getGeneratedClasses()) { + classNamesToBeValidated.add(DotName.createSimple(generatedClass)); + } + } + // JAX-RS methods are handled differently by the transformer so those need to be gathered here. // Note: The focus only on methods is basically an incomplete solution, since there could also be // class-level JAX-RS annotations but currently the transformer only looks at methods. diff --git a/extensions/hibernate-validator/deployment/src/test/java/io/quarkus/hibernate/validator/test/config/ConfigMappingValidatorTest.java b/extensions/hibernate-validator/deployment/src/test/java/io/quarkus/hibernate/validator/test/config/ConfigMappingValidatorTest.java new file mode 100644 index 0000000000000..ec8b70552d843 --- /dev/null +++ b/extensions/hibernate-validator/deployment/src/test/java/io/quarkus/hibernate/validator/test/config/ConfigMappingValidatorTest.java @@ -0,0 +1,41 @@ +package io.quarkus.hibernate.validator.test.config; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import javax.inject.Inject; +import javax.validation.constraints.Max; + +import org.eclipse.microprofile.config.Config; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.ConfigValidationException; +import io.smallrye.config.SmallRyeConfig; + +public class ConfigMappingValidatorTest { + @RegisterExtension + static final QuarkusUnitTest UNIT_TEST = new QuarkusUnitTest().setArchiveProducer( + () -> ShrinkWrap.create(JavaArchive.class) + .addAsResource(new StringAsset("server.host=localhost\n"), "application.properties")); + + @Inject + Config config; + + @Test + void validator() { + assertThrows(ConfigValidationException.class, + () -> config.unwrap(SmallRyeConfig.class).getConfigMapping(Server.class), + "server.host must be less than or equal to 3"); + } + + @ConfigMapping(prefix = "server") + public interface Server { + @Max(3) + String host(); + } +} diff --git a/extensions/hibernate-validator/runtime/pom.xml b/extensions/hibernate-validator/runtime/pom.xml index faa299a71afca..a07425441a1e4 100644 --- a/extensions/hibernate-validator/runtime/pom.xml +++ b/extensions/hibernate-validator/runtime/pom.xml @@ -30,6 +30,10 @@ org.glassfish jakarta.el + + io.smallrye.config + smallrye-config-validator + org.jboss.resteasy resteasy-core diff --git a/extensions/hibernate-validator/runtime/src/main/java/io/quarkus/hibernate/validator/runtime/HibernateBeanValidationConfigValidator.java b/extensions/hibernate-validator/runtime/src/main/java/io/quarkus/hibernate/validator/runtime/HibernateBeanValidationConfigValidator.java new file mode 100644 index 0000000000000..13aafb261b8c6 --- /dev/null +++ b/extensions/hibernate-validator/runtime/src/main/java/io/quarkus/hibernate/validator/runtime/HibernateBeanValidationConfigValidator.java @@ -0,0 +1,12 @@ +package io.quarkus.hibernate.validator.runtime; + +import javax.validation.Validator; + +import io.smallrye.config.validator.BeanValidationConfigValidator; + +public class HibernateBeanValidationConfigValidator implements BeanValidationConfigValidator { + @Override + public Validator getValidator() { + return ValidatorHolder.getValidator(); + } +} diff --git a/extensions/hibernate-validator/runtime/src/main/resources/META-INF/services/io.smallrye.config.ConfigValidator b/extensions/hibernate-validator/runtime/src/main/resources/META-INF/services/io.smallrye.config.ConfigValidator new file mode 100644 index 0000000000000..cf5de21457647 --- /dev/null +++ b/extensions/hibernate-validator/runtime/src/main/resources/META-INF/services/io.smallrye.config.ConfigValidator @@ -0,0 +1,2 @@ +#io.smallrye.config.validator.BeanValidationConfigValidatorImpl +io.quarkus.hibernate.validator.runtime.HibernateBeanValidationConfigValidator diff --git a/integration-tests/smallrye-config/pom.xml b/integration-tests/smallrye-config/pom.xml index 67d90fc4324af..cf5a8c414e689 100644 --- a/integration-tests/smallrye-config/pom.xml +++ b/integration-tests/smallrye-config/pom.xml @@ -15,6 +15,10 @@ Quarkus - Integration Tests - SmallRye Config + + io.quarkus + quarkus-hibernate-validator + io.quarkus quarkus-config-yaml @@ -47,6 +51,19 @@ + + io.quarkus + quarkus-hibernate-validator-deployment + ${project.version} + pom + test + + + * + * + + + io.quarkus quarkus-config-yaml-deployment diff --git a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Cloud.java b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Cloud.java new file mode 100644 index 0000000000000..bacd07dad7502 --- /dev/null +++ b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Cloud.java @@ -0,0 +1,10 @@ +package io.quarkus.it.smallrye.config; + +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithParentName; + +@ConfigMapping(prefix = "cloud") +public interface Cloud { + @WithParentName + Server server(); +} diff --git a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Server.java b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Server.java index b2a8e55f2f432..a266a558e11e4 100644 --- a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Server.java +++ b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/Server.java @@ -5,6 +5,11 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.OptionalInt; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.Size; import com.fasterxml.jackson.annotation.JsonProperty; @@ -22,6 +27,7 @@ public interface Server { String host(); @JsonProperty + @Min(8000) int port(); @JsonProperty @@ -48,6 +54,9 @@ public interface Server { @JsonProperty Log log(); + @JsonProperty + Info info(); + interface Form { @JsonProperty String loginPage(); @@ -77,6 +86,10 @@ interface Ssl { interface Proxy { @JsonProperty boolean enable(); + + @JsonProperty + @Max(10) + int timeout(); } interface Log { @@ -99,6 +112,10 @@ interface Log { @JsonProperty Period period(); + @JsonProperty + @Max(15) + int days(); + @RegisterForReflection enum Pattern { COMMON, @@ -113,14 +130,37 @@ interface Cors { List origins(); @JsonProperty - List methods(); + List<@Size(min = 2) String> methods(); interface Origin { @JsonProperty + @Size(min = 5) String host(); @JsonProperty + @Min(8000) int port(); } } + + interface Info { + @JsonProperty + Optional<@Size(max = 3) String> name(); + + @JsonProperty + @Max(3) + OptionalInt code(); + + @JsonProperty + Optional> alias(); + + @JsonProperty + Map admins(); + + interface Admin { + @JsonProperty + @Size(max = 3) + String username(); + } + } } diff --git a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/ServerResource.java b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/ServerResource.java index 3bd44522eae7d..5be4bf80738e0 100644 --- a/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/ServerResource.java +++ b/integration-tests/smallrye-config/src/main/java/io/quarkus/it/smallrye/config/ServerResource.java @@ -1,14 +1,23 @@ package io.quarkus.it.smallrye.config; import javax.inject.Inject; +import javax.json.Json; +import javax.json.JsonArrayBuilder; +import javax.json.JsonObjectBuilder; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.core.Response; +import org.eclipse.microprofile.config.Config; import org.eclipse.microprofile.config.inject.ConfigProperties; +import io.smallrye.config.ConfigValidationException; +import io.smallrye.config.SmallRyeConfig; + @Path("/server") public class ServerResource { + @Inject + Config config; @Inject Server server; @Inject @@ -25,4 +34,24 @@ public Response getServer() { public Response getServerProperties() { return Response.ok(serverProperties).build(); } + + @GET + @Path("/validator/cloud") + public Response validator() { + try { + config.unwrap(SmallRyeConfig.class).getConfigMapping(Cloud.class, "cloud"); + } catch (ConfigValidationException e) { + JsonArrayBuilder jsonArrayBuilder = Json.createArrayBuilder(); + for (int i = 0; i < e.getProblemCount(); i++) { + jsonArrayBuilder.add(e.getProblem(i).getMessage()); + } + JsonObjectBuilder jsonObjectBuilder = Json.createObjectBuilder(); + jsonObjectBuilder.add("errors", jsonArrayBuilder); + return Response.ok().entity(jsonObjectBuilder.build().toString()).build(); + } catch (Exception e) { + e.printStackTrace(); + } + + return Response.serverError().build(); + } } diff --git a/integration-tests/smallrye-config/src/main/resources/application.yaml b/integration-tests/smallrye-config/src/main/resources/application.yaml index ee5a005d2cfee..65a19799838e2 100644 --- a/integration-tests/smallrye-config/src/main/resources/application.yaml +++ b/integration-tests/smallrye-config/src/main/resources/application.yaml @@ -25,6 +25,49 @@ server: log: period: P1D + days: 10 + +cloud: + host: localhost + port: 8080 + timeout: 60s + io-threads: 200 + + form: + login-page: login.html + error-page: error.html + landing-page: index.html + + ssl: + port: 8443 + certificate: certificate + + cors: + origins: + - host: some-server + port: 9000 + - host: localhost + port: 1 + methods: + - GET + - POST + + proxy: + enable: true + timeout: 20 + + log: + period: P1D + days: 20 + + info: + name: Bond + code: 007 + alias: + - James + admins: + root: + username: root profile: main: diff --git a/integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/ServerResourceTest.java b/integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/ServerResourceTest.java index b2ea4c38ac4a5..f8c230723c40f 100644 --- a/integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/ServerResourceTest.java +++ b/integration-tests/smallrye-config/src/test/java/io/quarkus/it/smallrye/config/ServerResourceTest.java @@ -1,15 +1,33 @@ package io.quarkus.it.smallrye.config; import static io.restassured.RestAssured.given; +import static javax.ws.rs.core.HttpHeaders.ACCEPT; +import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static javax.ws.rs.core.Response.Status.OK; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.hasSize; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import io.quarkus.test.junit.QuarkusTest; +import io.restassured.RestAssured; +import io.restassured.http.Header; @QuarkusTest class ServerResourceTest { + @BeforeAll + static void beforeAll() { + RestAssured.filters( + (requestSpec, responseSpec, ctx) -> { + requestSpec.header(new Header(CONTENT_TYPE, APPLICATION_JSON)); + requestSpec.header(new Header(ACCEPT, APPLICATION_JSON)); + return ctx.next(requestSpec, responseSpec); + }); + } + @Test void mapping() { given() @@ -46,4 +64,19 @@ void properties() { .body("host", equalTo("localhost")) .body("port", equalTo(8080)); } + + @Test + void invalid() { + given().get("/server/validator/{prefix}", "cloud") + .then() + .statusCode(OK.getStatusCode()) + .body("errors", hasSize(7)) + .body("errors", hasItem("cloud.log.days must be less than or equal to 15")) + .body("errors", hasItem("cloud.cors.origins[1].port must be greater than or equal to 8000")) + .body("errors", hasItem("cloud.info.name size must be between 0 and 3")) + .body("errors", hasItem("cloud.info.code must be less than or equal to 3")) + .body("errors", hasItem("cloud.info.alias[0] size must be between 0 and 3")) + .body("errors", hasItem("cloud.info.admins.root.username size must be between 0 and 3")) + .body("errors", hasItem("cloud.proxy.timeout must be less than or equal to 10")); + } } diff --git a/tcks/microprofile-config/pom.xml b/tcks/microprofile-config/pom.xml index 9d61669968eb8..691d6e160d803 100644 --- a/tcks/microprofile-config/pom.xml +++ b/tcks/microprofile-config/pom.xml @@ -32,7 +32,6 @@ Bob - false dummy Tennis 120 From f80f30c34d72ff6e3d7c1a670e76027952c65439 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 17 May 2021 11:44:45 +0100 Subject: [PATCH 0096/2077] Inner classes mapped as entity should be static --- .../MultiplePersistenceUnitsClassLevelAnnotationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/multiplepersistenceunits/MultiplePersistenceUnitsClassLevelAnnotationTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/multiplepersistenceunits/MultiplePersistenceUnitsClassLevelAnnotationTest.java index 8b9be29bb75d1..36278068a0136 100644 --- a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/multiplepersistenceunits/MultiplePersistenceUnitsClassLevelAnnotationTest.java +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/multiplepersistenceunits/MultiplePersistenceUnitsClassLevelAnnotationTest.java @@ -32,7 +32,7 @@ public void testInvalidConfiguration() { @Entity @PersistenceUnit("inventory") - public class EntityWithClassLevelPersistenceUnit { + public static class EntityWithClassLevelPersistenceUnit { private long id; From 88e771e993341e820606dda43c6958e26089c723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Thu, 15 Apr 2021 17:50:51 +0200 Subject: [PATCH 0097/2077] Handle Class.getMethods() returning multiple getters with just the return type differring This can happen when getters are defined in an implement interface with a different return type (a supertype); in that case we get two getters for the same property in the array returned by Class.getMethods(). Since the order of methods in that array is unspecified, in some cases it will work (super method then overridden method => we keep the overridden method), and in others it won't (overridden method then super method => we keep the super method). I wasn't able to reproduce the problem in a unit test, but I know it happens with my JVM (OpenJDK 11) for JaxbEmbeddable.getAttributes(), and it caused BytecodeRecorder to fail. Changing the loop to keep the most specific getter only fixes the problem. --- .../io/quarkus/deployment/recording/PropertyUtils.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/recording/PropertyUtils.java b/core/deployment/src/main/java/io/quarkus/deployment/recording/PropertyUtils.java index 0d23928a7f080..835c7aff70a0a 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/recording/PropertyUtils.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/recording/PropertyUtils.java @@ -28,7 +28,12 @@ public Property[] apply(Class type) { if (i.getName().startsWith("get") && i.getName().length() > 3 && i.getParameterCount() == 0 && i.getReturnType() != void.class) { String name = Character.toLowerCase(i.getName().charAt(3)) + i.getName().substring(4); - getters.put(name, i); + Method existingGetter = getters.get(name); + // In some cases the overridden methods from supertypes can also appear in the array (for some reason). + // We want the most specific methods. + if (existingGetter == null || existingGetter.getReturnType().isAssignableFrom(i.getReturnType())) { + getters.put(name, i); + } } else if (i.getName().startsWith("is") && i.getName().length() > 3 && i.getParameterCount() == 0 && i.getReturnType() == boolean.class) { String name = Character.toLowerCase(i.getName().charAt(2)) + i.getName().substring(3); From 6aacf364fc2884b7cb7a2fbfb4fd742fdc277343 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Mon, 17 May 2021 14:39:55 +0300 Subject: [PATCH 0098/2077] Apply minor polish to RESTEasy Reactive extension using Java 11 Collection methods --- .../ResteasyServerCommonProcessor.java | 21 +++++++++---------- .../JsonDefaultProducersHandler.java | 4 +--- .../ResteasyReactiveJsonbProcessor.java | 5 ++--- .../QuarkusServerEndpointIndexer.java | 7 ++----- .../runtime/NotFoundExceptionMapper.java | 2 +- 5 files changed, 16 insertions(+), 23 deletions(-) diff --git a/extensions/resteasy-classic/resteasy-server-common/deployment/src/main/java/io/quarkus/resteasy/server/common/deployment/ResteasyServerCommonProcessor.java b/extensions/resteasy-classic/resteasy-server-common/deployment/src/main/java/io/quarkus/resteasy/server/common/deployment/ResteasyServerCommonProcessor.java index c149679b7abd2..21224578614bc 100755 --- a/extensions/resteasy-classic/resteasy-server-common/deployment/src/main/java/io/quarkus/resteasy/server/common/deployment/ResteasyServerCommonProcessor.java +++ b/extensions/resteasy-classic/resteasy-server-common/deployment/src/main/java/io/quarkus/resteasy/server/common/deployment/ResteasyServerCommonProcessor.java @@ -5,7 +5,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -90,24 +89,22 @@ public class ResteasyServerCommonProcessor { private static final DotName JSONB_ANNOTATION = DotName.createSimple("javax.json.bind.annotation.JsonbAnnotation"); - private static final DotName[] METHOD_ANNOTATIONS = { + private static final List METHOD_ANNOTATIONS = List.of( ResteasyDotNames.GET, ResteasyDotNames.HEAD, ResteasyDotNames.DELETE, ResteasyDotNames.OPTIONS, ResteasyDotNames.PATCH, ResteasyDotNames.POST, - ResteasyDotNames.PUT, - }; + ResteasyDotNames.PUT); - private static final DotName[] RESTEASY_PARAM_ANNOTATIONS = { + private static final List RESTEASY_PARAM_ANNOTATIONS = List.of( ResteasyDotNames.RESTEASY_QUERY_PARAM, ResteasyDotNames.RESTEASY_FORM_PARAM, ResteasyDotNames.RESTEASY_COOKIE_PARAM, ResteasyDotNames.RESTEASY_PATH_PARAM, ResteasyDotNames.RESTEASY_HEADER_PARAM, - ResteasyDotNames.RESTEASY_MATRIX_PARAM, - }; + ResteasyDotNames.RESTEASY_MATRIX_PARAM); /** * JAX-RS configuration. @@ -709,8 +706,9 @@ private static String packageName(DotName dotName) { private static void checkParameterNames(IndexView index, List additionalJaxRsResourceMethodParamAnnotations) { - final List methodParameterAnnotations = new ArrayList<>(RESTEASY_PARAM_ANNOTATIONS.length); - methodParameterAnnotations.addAll(Arrays.asList(RESTEASY_PARAM_ANNOTATIONS)); + final List methodParameterAnnotations = new ArrayList<>( + RESTEASY_PARAM_ANNOTATIONS.size() + additionalJaxRsResourceMethodParamAnnotations.size()); + methodParameterAnnotations.addAll(RESTEASY_PARAM_ANNOTATIONS); for (AdditionalJaxRsResourceMethodParamAnnotations annotations : additionalJaxRsResourceMethodParamAnnotations) { methodParameterAnnotations.addAll(annotations.getAnnotationClasses()); } @@ -790,8 +788,9 @@ private static void registerReflectionForSerialization(BuildProducer annotations = new ArrayList<>(METHOD_ANNOTATIONS.length); - annotations.addAll(Arrays.asList(METHOD_ANNOTATIONS)); + final List annotations = new ArrayList<>( + METHOD_ANNOTATIONS.size() + additionalJaxRsResourceMethodAnnotations.size()); + annotations.addAll(METHOD_ANNOTATIONS); for (AdditionalJaxRsResourceMethodAnnotationsBuildItem additionalJaxRsResourceMethodAnnotation : additionalJaxRsResourceMethodAnnotations) { annotations.addAll(additionalJaxRsResourceMethodAnnotation.getAnnotationClasses()); } diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/deployment/src/main/java/io/quarkus/resteasy/reactive/common/deployment/JsonDefaultProducersHandler.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/deployment/src/main/java/io/quarkus/resteasy/reactive/common/deployment/JsonDefaultProducersHandler.java index f682990015fa7..69b2793c5f7f8 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/deployment/src/main/java/io/quarkus/resteasy/reactive/common/deployment/JsonDefaultProducersHandler.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/deployment/src/main/java/io/quarkus/resteasy/reactive/common/deployment/JsonDefaultProducersHandler.java @@ -5,9 +5,7 @@ import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.MAP; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.SET; -import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Set; @@ -21,7 +19,7 @@ public class JsonDefaultProducersHandler implements DefaultProducesHandler { private static final List PRODUCES_APPLICATION_JSON = Collections.singletonList(MediaType.APPLICATION_JSON_TYPE); - private static final Set SUPPORTED_JAVA_TYPES = new HashSet<>(Arrays.asList(COLLECTION, LIST, SET, MAP)); + private static final Set SUPPORTED_JAVA_TYPES = Set.of(COLLECTION, LIST, SET, MAP); @Override public List handle(Context context) { diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/deployment/src/main/java/io/quarkus/resteasy/reactive/jsonb/deployment/processor/ResteasyReactiveJsonbProcessor.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/deployment/src/main/java/io/quarkus/resteasy/reactive/jsonb/deployment/processor/ResteasyReactiveJsonbProcessor.java index b6dc3c28e6d3f..05b9500c13f28 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/deployment/src/main/java/io/quarkus/resteasy/reactive/jsonb/deployment/processor/ResteasyReactiveJsonbProcessor.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/deployment/src/main/java/io/quarkus/resteasy/reactive/jsonb/deployment/processor/ResteasyReactiveJsonbProcessor.java @@ -1,6 +1,5 @@ package io.quarkus.resteasy.reactive.jsonb.deployment.processor; -import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -22,11 +21,11 @@ public class ResteasyReactiveJsonbProcessor { - private static final List VERTX_SERIALIZERS = Arrays.asList( + private static final List VERTX_SERIALIZERS = List.of( VertxJson.JsonObjectSerializer.class.getName(), VertxJson.JsonArraySerializer.class.getName()); - private static final List VERTX_DESERIALIZERS = Arrays.asList( + private static final List VERTX_DESERIALIZERS = List.of( VertxJson.JsonObjectDeserializer.class.getName(), VertxJson.JsonArrayDeserializer.class.getName()); diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/QuarkusServerEndpointIndexer.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/QuarkusServerEndpointIndexer.java index f5bf0335d41f4..6b0492f2424f1 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/QuarkusServerEndpointIndexer.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/QuarkusServerEndpointIndexer.java @@ -3,10 +3,7 @@ import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.STRING; import java.lang.reflect.Modifier; -import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -59,10 +56,10 @@ public class QuarkusServerEndpointIndexer private final Map multipartGeneratedPopulators = new HashMap<>(); private final Predicate applicationClassPredicate; - private static final Set CONTEXT_TYPES = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( + private static final Set CONTEXT_TYPES = Set.of( DotName.createSimple(HttpServerRequest.class.getName()), DotName.createSimple(HttpServerResponse.class.getName()), - DotName.createSimple(RoutingContext.class.getName())))); + DotName.createSimple(RoutingContext.class.getName())); QuarkusServerEndpointIndexer(Builder builder) { super(builder); diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/NotFoundExceptionMapper.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/NotFoundExceptionMapper.java index f0953b12a33fc..79b111d710ad0 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/NotFoundExceptionMapper.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/NotFoundExceptionMapper.java @@ -51,7 +51,7 @@ public class NotFoundExceptionMapper { private final static Variant JSON_VARIANT = new Variant(MediaType.APPLICATION_JSON_TYPE, (String) null, null); private final static Variant HTML_VARIANT = new Variant(MediaType.TEXT_HTML_TYPE, (String) null, null); - private final static List VARIANTS = Arrays.asList(JSON_VARIANT, HTML_VARIANT); + private final static List VARIANTS = List.of(JSON_VARIANT, HTML_VARIANT); static volatile List> classMappers; private volatile static String httpRoot = ""; From 3f86904f44c2068ede4cf83c4603f54a2cfafd74 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Mon, 17 May 2021 13:51:37 +0200 Subject: [PATCH 0099/2077] Upgrade to Flyway 7.9.0 --- bom/application/pom.xml | 2 +- .../io/quarkus/flyway/runtime/QuarkusPathLocationScanner.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 4133cbd084c0e..5bcf9991314be 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -162,7 +162,7 @@ 1.6.5 1.0.9 5.11.0.202103091610-r - 7.8.2 + 7.9.0 1.0.9 4.3.5 1.28 diff --git a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/QuarkusPathLocationScanner.java b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/QuarkusPathLocationScanner.java index f2f517c17338e..509145744666b 100644 --- a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/QuarkusPathLocationScanner.java +++ b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/QuarkusPathLocationScanner.java @@ -42,7 +42,7 @@ public QuarkusPathLocationScanner(Collection locations) { scannedResources.add(new ClassPathResource(null, migrationFile, classLoader, StandardCharsets.UTF_8)); } else if (migrationFile.startsWith(Location.FILESYSTEM_PREFIX)) { if (fileSystemScanner == null) { - fileSystemScanner = new FileSystemScanner(StandardCharsets.UTF_8, false); + fileSystemScanner = new FileSystemScanner(StandardCharsets.UTF_8, false, false, false); } LOGGER.debugf("Checking %s for migration files", migrationFile); Collection resources = fileSystemScanner.scanForResources(new Location(migrationFile)); From deac83007c8a72649c1e5bf0d92aaa52c975a582 Mon Sep 17 00:00:00 2001 From: Alexey Loubyansky Date: Mon, 17 May 2021 10:31:21 +0200 Subject: [PATCH 0100/2077] Add artifact coords and enable resource filtering for quarkus-extension.yaml --- core/runtime/pom.xml | 6 ++++++ .../resources/META-INF/quarkus-extension.yaml | 5 +++++ .../META-INF/quarkus-extension.yaml.template | 4 ---- docs/src/main/asciidoc/writing-extensions.adoc | 3 --- ...sion.yaml.template => quarkus-extension.yaml} | 1 + ...sion.yaml.template => quarkus-extension.yaml} | 1 + ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- .../resources/META-INF/quarkus-extension.yaml | 5 +++++ .../META-INF/quarkus-extension.yaml.template | 4 ---- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 1 + ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 1 + ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- .../resources/META-INF/quarkus-extension.yaml | 5 +++++ .../META-INF/quarkus-extension.yaml.template | 4 ---- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 1 + ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 1 + ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 1 + ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 1 + ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 1 + ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- .../resources/META-INF/quarkus-extension.yaml | 8 ++++++++ .../META-INF/quarkus-extension.yaml.template | 7 ------- extensions/oidc-client-filter/deployment/pom.xml | 4 ++-- extensions/oidc-client-filter/pom.xml | 4 ++-- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- extensions/oidc-client-reactive-filter/pom.xml | 4 ++-- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- extensions/oidc-client/deployment/pom.xml | 6 +++--- extensions/oidc-client/pom.xml | 4 ++-- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- extensions/oidc-common/pom.xml | 4 ++-- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- extensions/oidc-token-propagation/pom.xml | 4 ++-- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- extensions/opentelemetry-exporter-jaeger/pom.xml | 4 ++-- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- extensions/opentelemetry/pom.xml | 4 ++-- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 2 +- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 2 +- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- .../resources/META-INF/quarkus-extension.yaml | 5 +++++ .../META-INF/quarkus-extension.yaml.template | 4 ---- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 1 + ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- extensions/pom.xml | 6 ++++++ ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 2 +- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- .../resources/META-INF/quarkus-extension.yaml | 5 +++++ .../META-INF/quarkus-extension.yaml.template | 4 ---- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 1 + ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- .../resources/META-INF/quarkus-extension.yaml | 5 +++++ .../META-INF/quarkus-extension.yaml.template | 4 ---- ...sion.yaml.template => quarkus-extension.yaml} | 1 + ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 1 + ...sion.yaml.template => quarkus-extension.yaml} | 2 +- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- .../rest-client-reactive/pom.xml | 4 ++-- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 1 + ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 1 + ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- extensions/spring-data-rest/pom.xml | 4 ++-- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 2 +- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 1 + ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- .../quarkus/maven/ExtensionDescriptorMojo.java | 16 ++-------------- .../resources/META-INF/quarkus-extension.yaml | 4 ++++ .../META-INF/quarkus-extension.yaml.template | 6 ------ test-framework/jacoco/runtime/pom.xml | 6 ++++++ ...sion.yaml.template => quarkus-extension.yaml} | 3 ++- 221 files changed, 442 insertions(+), 250 deletions(-) create mode 100644 core/runtime/src/main/resources/META-INF/quarkus-extension.yaml delete mode 100644 core/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename extensions/agroal/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (76%) rename extensions/amazon-alexa/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (70%) rename extensions/amazon-lambda-http/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (68%) rename extensions/amazon-lambda-rest/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (69%) rename extensions/amazon-lambda-xray/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (70%) create mode 100644 extensions/amazon-lambda/common-runtime/src/main/resources/META-INF/quarkus-extension.yaml delete mode 100644 extensions/amazon-lambda/common-runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename extensions/amazon-lambda/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (81%) rename extensions/amazon-services/common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (70%) rename extensions/amazon-services/dynamodb/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (67%) rename extensions/amazon-services/iam/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (64%) rename extensions/amazon-services/kms/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (64%) rename extensions/amazon-services/s3/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (63%) rename extensions/amazon-services/ses/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (64%) rename extensions/amazon-services/sns/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (64%) rename extensions/amazon-services/sqs/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (64%) rename extensions/amazon-services/ssm/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (64%) rename extensions/apache-httpclient/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (57%) rename extensions/arc/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (70%) rename extensions/artemis-core/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (66%) rename extensions/artemis-jms/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (62%) rename extensions/avro/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (58%) rename extensions/azure-functions-http/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (81%) rename extensions/cache/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (60%) rename extensions/caffeine/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (52%) rename extensions/config-yaml/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (81%) rename extensions/consul-config/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (60%) rename extensions/container-image/container-image-docker/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (59%) rename extensions/container-image/container-image-jib/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (58%) rename extensions/container-image/container-image-openshift/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (60%) rename extensions/container-image/container-image-s2i/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (58%) rename extensions/container-image/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (60%) rename extensions/datasource/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (58%) rename extensions/elasticsearch-rest-client-common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (58%) rename extensions/elasticsearch-rest-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (67%) rename extensions/elasticsearch-rest-high-level-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (68%) rename extensions/elytron-security-common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (57%) rename extensions/elytron-security-jdbc/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (64%) rename extensions/elytron-security-ldap/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (65%) rename extensions/elytron-security-oauth2/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (65%) rename extensions/elytron-security-properties-file/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (51%) rename extensions/elytron-security/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (56%) rename extensions/flyway/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (62%) rename extensions/funqy/funqy-amazon-lambda/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (83%) rename extensions/funqy/funqy-google-cloud-functions/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (86%) rename extensions/funqy/funqy-http/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (80%) rename extensions/funqy/funqy-knative-events/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (83%) create mode 100644 extensions/funqy/funqy-server-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml delete mode 100644 extensions/funqy/funqy-server-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename extensions/google-cloud-functions-http/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (83%) rename extensions/google-cloud-functions/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (82%) mode change 100755 => 100644 rename extensions/grpc-common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (62%) rename extensions/grpc/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (55%) rename extensions/hibernate-envers/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (68%) rename extensions/hibernate-orm/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (68%) rename extensions/hibernate-reactive/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (64%) rename extensions/hibernate-search-orm-elasticsearch/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (80%) rename extensions/hibernate-validator/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (72%) rename extensions/infinispan-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (69%) rename extensions/jackson/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (53%) rename extensions/jaeger/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (63%) rename extensions/jaxb/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (59%) rename extensions/jaxp/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (56%) rename extensions/jdbc/jdbc-db2/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (56%) rename extensions/jdbc/jdbc-derby/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (57%) rename extensions/jdbc/jdbc-h2/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (64%) rename extensions/jdbc/jdbc-mariadb/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (58%) rename extensions/jdbc/jdbc-mssql/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (63%) rename extensions/jdbc/jdbc-mysql/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (57%) rename extensions/jdbc/jdbc-oracle/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (66%) rename extensions/jdbc/jdbc-postgresql/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (60%) rename extensions/jgit/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (58%) rename extensions/jsch/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (66%) rename extensions/jsonb/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (64%) rename extensions/jsonp/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (55%) rename extensions/kafka-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (61%) rename extensions/kafka-streams/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (65%) rename extensions/keycloak-admin-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (64%) rename extensions/keycloak-authorization/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (78%) rename extensions/kotlin/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (77%) rename extensions/kubernetes-client/runtime-internal/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (61%) rename extensions/kubernetes-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (71%) rename extensions/kubernetes-config/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (63%) rename extensions/kubernetes-service-binding/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (57%) rename extensions/kubernetes/minikube/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (62%) rename extensions/kubernetes/openshift/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (63%) rename extensions/kubernetes/vanilla/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (60%) rename extensions/liquibase/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (63%) rename extensions/logging-gelf/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (66%) rename extensions/logging-json/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (51%) rename extensions/logging-sentry/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (72%) rename extensions/mailer/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (61%) rename extensions/micrometer-registry-prometheus/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (72%) rename extensions/micrometer/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (68%) rename extensions/mongodb-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (66%) rename extensions/mutiny/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (64%) rename extensions/narayana-jta/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (73%) rename extensions/narayana-stm/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (77%) rename extensions/neo4j/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (65%) create mode 100644 extensions/netty/runtime/src/main/resources/META-INF/quarkus-extension.yaml delete mode 100644 extensions/netty/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename extensions/oidc-client-filter/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (73%) rename extensions/oidc-client-reactive-filter/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (76%) rename extensions/oidc-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (70%) rename extensions/oidc-common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (63%) rename extensions/oidc-token-propagation/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (74%) rename extensions/oidc/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (67%) rename extensions/openshift-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (65%) rename extensions/opentelemetry-exporter-jaeger/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (74%) rename extensions/opentelemetry/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (70%) rename extensions/panache/hibernate-orm-panache-common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (74%) rename extensions/panache/hibernate-orm-panache-kotlin/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (72%) rename extensions/panache/hibernate-orm-panache/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (70%) rename extensions/panache/hibernate-orm-rest-data-panache/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (74%) rename extensions/panache/hibernate-reactive-panache-common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (75%) rename extensions/panache/hibernate-reactive-panache/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (64%) create mode 100644 extensions/panache/mongodb-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml delete mode 100644 extensions/panache/mongodb-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename extensions/panache/mongodb-panache-kotlin/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (64%) rename extensions/panache/mongodb-panache/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (69%) rename extensions/panache/mongodb-rest-data-panache/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (72%) rename extensions/panache/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (76%) rename extensions/picocli/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (81%) rename extensions/quartz/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (67%) rename extensions/qute/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (64%) rename extensions/reactive-datasource/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (62%) rename extensions/reactive-db2-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (73%) rename extensions/reactive-messaging-http/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (66%) rename extensions/reactive-mysql-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (74%) rename extensions/reactive-pg-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (74%) rename extensions/reactive-streams-operators/mutiny-reactive-streams-operators/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (66%) rename extensions/reactive-streams-operators/smallrye-reactive-streams-operators/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (86%) rename extensions/reactive-streams-operators/smallrye-reactive-type-converters/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (75%) rename extensions/redis-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (72%) rename extensions/resteasy-classic/rest-client-jackson/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (70%) rename extensions/resteasy-classic/rest-client-jaxb/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (68%) rename extensions/resteasy-classic/rest-client-jsonb/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (70%) rename extensions/resteasy-classic/rest-client-mutiny/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (70%) rename extensions/resteasy-classic/rest-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (68%) rename extensions/resteasy-classic/resteasy-common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (63%) rename extensions/resteasy-classic/resteasy-jackson/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (69%) rename extensions/resteasy-classic/resteasy-jaxb/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (64%) rename extensions/resteasy-classic/resteasy-jsonb/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (73%) rename extensions/resteasy-classic/resteasy-multipart/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (71%) create mode 100644 extensions/resteasy-classic/resteasy-mutiny-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml delete mode 100644 extensions/resteasy-classic/resteasy-mutiny-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename extensions/resteasy-classic/resteasy-mutiny/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (71%) rename extensions/resteasy-classic/resteasy-qute/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (82%) rename extensions/resteasy-classic/resteasy-server-common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (69%) rename extensions/resteasy-classic/resteasy/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (83%) rename extensions/resteasy-reactive/jaxrs-client-reactive/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (62%) create mode 100644 extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml delete mode 100644 extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson-common/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (50%) rename extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (86%) rename extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (85%) rename extensions/resteasy-reactive/quarkus-resteasy-reactive-links/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (83%) rename extensions/resteasy-reactive/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (76%) rename extensions/resteasy-reactive/quarkus-resteasy-reactive-qute/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (83%) rename extensions/resteasy-reactive/quarkus-resteasy-reactive-servlet/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (84%) rename extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (82%) rename extensions/resteasy-reactive/rest-client-reactive-jackson/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (85%) rename extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (82%) rename extensions/scala/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (74%) rename extensions/scheduler/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (67%) rename extensions/security-jpa/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (66%) rename extensions/security/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (64%) rename extensions/smallrye-context-propagation/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (78%) rename extensions/smallrye-fault-tolerance/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (75%) rename extensions/smallrye-graphql/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (72%) rename extensions/smallrye-health/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (75%) rename extensions/smallrye-jwt-build/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (70%) rename extensions/smallrye-jwt/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (69%) rename extensions/smallrye-metrics/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (74%) rename extensions/smallrye-openapi/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (67%) rename extensions/smallrye-opentracing/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (72%) rename extensions/smallrye-reactive-messaging-amqp/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (69%) rename extensions/smallrye-reactive-messaging-kafka/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (70%) rename extensions/smallrye-reactive-messaging-mqtt/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (61%) rename extensions/smallrye-reactive-messaging/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (77%) rename extensions/spring-boot-properties/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (70%) rename extensions/spring-cache/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (69%) rename extensions/spring-cloud-config-client/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (74%) rename extensions/spring-data-jpa/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (68%) rename extensions/spring-data-rest/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (72%) rename extensions/spring-di/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (66%) rename extensions/spring-scheduled/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (68%) rename extensions/spring-security/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (70%) rename extensions/spring-web/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (83%) rename extensions/swagger-ui/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (63%) rename extensions/tika/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (62%) rename extensions/undertow/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (61%) rename extensions/vault/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (69%) rename extensions/vertx-core/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (66%) rename extensions/vertx-graphql/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (63%) rename extensions/vertx-http/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (70%) rename extensions/vertx-web/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (64%) rename extensions/vertx/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (67%) rename extensions/webjars-locator/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (61%) rename extensions/websockets/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (84%) create mode 100644 integration-tests/gradle/src/test/resources/test-resources-in-build-steps/runtime/src/main/resources/META-INF/quarkus-extension.yaml delete mode 100644 integration-tests/gradle/src/test/resources/test-resources-in-build-steps/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename test-framework/jacoco/runtime/src/main/resources/META-INF/{quarkus-extension.yaml.template => quarkus-extension.yaml} (65%) diff --git a/core/runtime/pom.xml b/core/runtime/pom.xml index fbe98d297c5ec..1e2628a6a777a 100644 --- a/core/runtime/pom.xml +++ b/core/runtime/pom.xml @@ -111,6 +111,12 @@ + + + src/main/resources + true + + io.quarkus diff --git a/core/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/core/runtime/src/main/resources/META-INF/quarkus-extension.yaml new file mode 100644 index 0000000000000..7bd23be4118e0 --- /dev/null +++ b/core/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -0,0 +1,5 @@ +--- +artifact: ${project.groupId}:${project.artifactId}:${project.version} +name: "Quarkus - Core" +metadata: + unlisted: true \ No newline at end of file diff --git a/core/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/core/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template deleted file mode 100644 index e3d0c8f1f88be..0000000000000 --- a/core/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ /dev/null @@ -1,4 +0,0 @@ ---- -name: "Quarkus - Core" -metadata: - unlisted: true diff --git a/docs/src/main/asciidoc/writing-extensions.adoc b/docs/src/main/asciidoc/writing-extensions.adoc index 30e9c920fc6ea..5605484192038 100644 --- a/docs/src/main/asciidoc/writing-extensions.adoc +++ b/docs/src/main/asciidoc/writing-extensions.adoc @@ -535,9 +535,6 @@ TIP: The `name` parameter of the mojo is optional. If you do not specify it on the command line, the plugin will derive it from `extensionId` by replacing dashes with spaces and uppercasing each token. So you may consider omitting explicit `name` in some cases. -NOTE: You can also name your file `quarkus-extension.yaml.template` and the plugin will rename it for you. This can avoid problems with running Dev Mode tests in your IDE, as the IDE can overwrite -the modified file with the original. - // The following link should point to the mojo page once https://github.com/quarkusio/quarkusio.github.io/issues/265 is fixed Please refer to https://github.com/quarkusio/quarkus/blob/{quarkus-version}/devtools/maven/src/main/java/io/quarkus/maven/CreateExtensionMojo.java[CreateExtensionMojo JavaDoc] for all the available options of the mojo. diff --git a/extensions/agroal/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/agroal/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 76% rename from extensions/agroal/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/agroal/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 561e82bddd111..0144582e3b356 100644 --- a/extensions/agroal/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/agroal/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,5 +1,6 @@ --- name: "Agroal - Database connection pool" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: keywords: - "agroal" diff --git a/extensions/amazon-alexa/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/amazon-alexa/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 70% rename from extensions/amazon-alexa/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/amazon-alexa/runtime/src/main/resources/META-INF/quarkus-extension.yaml index e6ef0d321dc21..94df9bef06f78 100644 --- a/extensions/amazon-alexa/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/amazon-alexa/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,5 +1,6 @@ --- name: "Amazon Alexa" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: keywords: - "lambda" diff --git a/extensions/amazon-lambda-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/amazon-lambda-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 68% rename from extensions/amazon-lambda-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/amazon-lambda-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml index cff965b4c3da0..d26b340b6991f 100644 --- a/extensions/amazon-lambda-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/amazon-lambda-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "AWS Lambda HTTP" metadata: keywords: @@ -10,4 +11,4 @@ metadata: categories: - "cloud" guide: "https://quarkus.io/guides/amazon-lambda-http" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/amazon-lambda-rest/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/amazon-lambda-rest/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 69% rename from extensions/amazon-lambda-rest/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/amazon-lambda-rest/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 01e578e12c75e..8caf7277ca0b6 100644 --- a/extensions/amazon-lambda-rest/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/amazon-lambda-rest/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "AWS Lambda Gateway REST API" metadata: keywords: @@ -10,4 +11,4 @@ metadata: categories: - "cloud" guide: "https://quarkus.io/guides/amazon-lambda-http" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/amazon-lambda-xray/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/amazon-lambda-xray/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 70% rename from extensions/amazon-lambda-xray/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/amazon-lambda-xray/runtime/src/main/resources/META-INF/quarkus-extension.yaml index a0b9c03843af7..b68cb8deb0e6a 100644 --- a/extensions/amazon-lambda-xray/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/amazon-lambda-xray/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "AWS Lambda X-Ray" metadata: keywords: @@ -9,4 +10,4 @@ metadata: guide: "https://quarkus.io/guides/amazon-lambda#tracing-with-aws-xray-and-graalvm" categories: - "cloud" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/amazon-lambda/common-runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/amazon-lambda/common-runtime/src/main/resources/META-INF/quarkus-extension.yaml new file mode 100644 index 0000000000000..6b0e3b5a5c856 --- /dev/null +++ b/extensions/amazon-lambda/common-runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -0,0 +1,5 @@ +--- +artifact: ${project.groupId}:${project.artifactId}:${project.version} +name: "AWS Lambda Common" +metadata: + unlisted: true \ No newline at end of file diff --git a/extensions/amazon-lambda/common-runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/amazon-lambda/common-runtime/src/main/resources/META-INF/quarkus-extension.yaml.template deleted file mode 100644 index 135c2caef5587..0000000000000 --- a/extensions/amazon-lambda/common-runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ /dev/null @@ -1,4 +0,0 @@ ---- -name: "AWS Lambda Common" -metadata: - unlisted: true diff --git a/extensions/amazon-lambda/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/amazon-lambda/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 81% rename from extensions/amazon-lambda/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/amazon-lambda/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 754fce2370f31..4e66c6d21a76a 100644 --- a/extensions/amazon-lambda/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/amazon-lambda/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "AWS Lambda" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: keywords: - "lambda" @@ -12,4 +13,4 @@ metadata: name: "amazon-lambda" kind: "example" languages: "java" - artifact: "io.quarkus:quarkus-project-core-extension-codestarts" + artifact: "io.quarkus:quarkus-project-core-extension-codestarts" \ No newline at end of file diff --git a/extensions/amazon-services/common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/amazon-services/common/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 70% rename from extensions/amazon-services/common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/amazon-services/common/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 3b027fd2b1bee..4ea5a1d78f630 100644 --- a/extensions/amazon-services/common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/amazon-services/common/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Amazon Services Common" metadata: keywords: diff --git a/extensions/amazon-services/dynamodb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/amazon-services/dynamodb/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 67% rename from extensions/amazon-services/dynamodb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/amazon-services/dynamodb/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 126d53eb2dd98..16a93626af4f8 100644 --- a/extensions/amazon-services/dynamodb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/amazon-services/dynamodb/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Amazon DynamoDB" metadata: keywords: @@ -9,4 +10,4 @@ metadata: guide: "https://quarkus.io/guides/amazon-dynamodb" categories: - "data" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/amazon-services/iam/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/amazon-services/iam/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 64% rename from extensions/amazon-services/iam/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/amazon-services/iam/runtime/src/main/resources/META-INF/quarkus-extension.yaml index b7c66cf0be5aa..b23a03f1897e5 100644 --- a/extensions/amazon-services/iam/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/amazon-services/iam/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Amazon IAM" metadata: keywords: @@ -8,4 +9,4 @@ metadata: guide: "https://quarkus.io/guides/amazon-iam" categories: - "data" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/amazon-services/kms/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/amazon-services/kms/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 64% rename from extensions/amazon-services/kms/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/amazon-services/kms/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 3a0f026ca12dd..37f5135cba20b 100644 --- a/extensions/amazon-services/kms/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/amazon-services/kms/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Amazon KMS" metadata: keywords: @@ -8,4 +9,4 @@ metadata: guide: "https://quarkus.io/guides/amazon-kms" categories: - "data" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/amazon-services/s3/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/amazon-services/s3/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 63% rename from extensions/amazon-services/s3/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/amazon-services/s3/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 2a0006eb4fe6e..837a6866e3f99 100644 --- a/extensions/amazon-services/s3/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/amazon-services/s3/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Amazon S3" metadata: keywords: @@ -8,4 +9,4 @@ metadata: guide: "https://quarkus.io/guides/amazon-s3" categories: - "data" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/amazon-services/ses/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/amazon-services/ses/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 64% rename from extensions/amazon-services/ses/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/amazon-services/ses/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 6d675841c165e..ea0cb367cd76e 100644 --- a/extensions/amazon-services/ses/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/amazon-services/ses/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Amazon SES" metadata: keywords: @@ -8,4 +9,4 @@ metadata: guide: "https://quarkus.io/guides/amazon-ses" categories: - "data" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/amazon-services/sns/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/amazon-services/sns/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 64% rename from extensions/amazon-services/sns/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/amazon-services/sns/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 7fefd8e559d77..507c0dc7dd321 100644 --- a/extensions/amazon-services/sns/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/amazon-services/sns/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Amazon SNS" metadata: keywords: @@ -8,4 +9,4 @@ metadata: guide: "https://quarkus.io/guides/amazon-sns" categories: - "data" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/amazon-services/sqs/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/amazon-services/sqs/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 64% rename from extensions/amazon-services/sqs/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/amazon-services/sqs/runtime/src/main/resources/META-INF/quarkus-extension.yaml index b2cf5891ea001..c033c7456bb2d 100644 --- a/extensions/amazon-services/sqs/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/amazon-services/sqs/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Amazon SQS" metadata: keywords: @@ -8,4 +9,4 @@ metadata: guide: "https://quarkus.io/guides/amazon-sqs" categories: - "data" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/amazon-services/ssm/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/amazon-services/ssm/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 64% rename from extensions/amazon-services/ssm/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/amazon-services/ssm/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 1c617de47fc13..8e077230c651f 100644 --- a/extensions/amazon-services/ssm/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/amazon-services/ssm/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Amazon SSM" metadata: keywords: @@ -8,4 +9,4 @@ metadata: guide: "https://quarkus.io/guides/amazon-ssm" categories: - "data" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/apache-httpclient/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/apache-httpclient/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 57% rename from extensions/apache-httpclient/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/apache-httpclient/runtime/src/main/resources/META-INF/quarkus-extension.yaml index b2c4d4a3c5822..5749641029979 100644 --- a/extensions/apache-httpclient/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/apache-httpclient/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: Apache HttpClient metadata: keywords: @@ -7,4 +8,4 @@ metadata: categories: - "web" status: "stable" - unlisted: true + unlisted: true \ No newline at end of file diff --git a/extensions/arc/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/arc/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 70% rename from extensions/arc/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/arc/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 0db0452421922..dedee9ee10bfc 100644 --- a/extensions/arc/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/arc/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "ArC" metadata: short-name: "CDI" @@ -11,4 +12,4 @@ metadata: categories: - "core" status: "stable" - unlisted: true + unlisted: true \ No newline at end of file diff --git a/extensions/artemis-core/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/artemis-core/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 66% rename from extensions/artemis-core/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/artemis-core/runtime/src/main/resources/META-INF/quarkus-extension.yaml index ec379d3d3faeb..4ddc982d6f4e8 100644 --- a/extensions/artemis-core/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/artemis-core/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Artemis Core" metadata: keywords: @@ -8,4 +9,4 @@ metadata: - "messaging" guide: "https://quarkus.io/guides/jms" status: "preview" - unlisted: true + unlisted: true \ No newline at end of file diff --git a/extensions/artemis-jms/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/artemis-jms/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 62% rename from extensions/artemis-jms/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/artemis-jms/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 8e11722d2a398..48b7ba7926ff8 100644 --- a/extensions/artemis-jms/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/artemis-jms/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Artemis JMS" metadata: keywords: @@ -7,4 +8,4 @@ metadata: guide: "https://quarkus.io/guides/jms" categories: - "messaging" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/avro/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/avro/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 58% rename from extensions/avro/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/avro/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 92e7acb940ab2..e7654c1788332 100644 --- a/extensions/avro/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/avro/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Apache Avro" metadata: keywords: @@ -6,4 +7,4 @@ metadata: guide: "https://quarkus.io/guides/kafka" categories: - "serialization" - status: "experimental" + status: "experimental" \ No newline at end of file diff --git a/extensions/azure-functions-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/azure-functions-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 81% rename from extensions/azure-functions-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/azure-functions-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 3ed3338f23954..f0bf92a0142b2 100644 --- a/extensions/azure-functions-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/azure-functions-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Azure Functions HTTP" metadata: keywords: @@ -12,4 +13,4 @@ metadata: name: "azure-functions-http" kind: "example" languages: "java" - artifact: "io.quarkus:quarkus-project-core-extension-codestarts" + artifact: "io.quarkus:quarkus-project-core-extension-codestarts" \ No newline at end of file diff --git a/extensions/cache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/cache/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 60% rename from extensions/cache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/cache/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 9159a9ee595b1..13a6c258a4e08 100644 --- a/extensions/cache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/cache/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Cache" metadata: keywords: @@ -7,4 +8,4 @@ metadata: guide: "https://quarkus.io/guides/cache" categories: - "data" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/caffeine/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/caffeine/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 52% rename from extensions/caffeine/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/caffeine/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 9274169fd6223..69eb3642e7ffd 100644 --- a/extensions/caffeine/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/caffeine/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Caffeine" metadata: keywords: @@ -6,4 +7,4 @@ metadata: categories: - "data" status: "stable" - unlisted: "true" + unlisted: "true" \ No newline at end of file diff --git a/extensions/config-yaml/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/config-yaml/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 81% rename from extensions/config-yaml/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/config-yaml/runtime/src/main/resources/META-INF/quarkus-extension.yaml index f8087d19aa159..4fb7816a51a5d 100644 --- a/extensions/config-yaml/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/config-yaml/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "YAML Configuration" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: keywords: - "config" @@ -13,4 +14,4 @@ metadata: languages: - "java" - "kotlin" - artifact: "io.quarkus:quarkus-project-core-extension-codestarts" + artifact: "io.quarkus:quarkus-project-core-extension-codestarts" \ No newline at end of file diff --git a/extensions/consul-config/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/consul-config/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 60% rename from extensions/consul-config/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/consul-config/runtime/src/main/resources/META-INF/quarkus-extension.yaml index f3d83e1724b11..ad747d75276c9 100644 --- a/extensions/consul-config/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/consul-config/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Consul Config" metadata: keywords: @@ -8,4 +9,4 @@ metadata: - "consul" categories: - "core" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/container-image/container-image-docker/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/container-image/container-image-docker/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 59% rename from extensions/container-image/container-image-docker/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/container-image/container-image-docker/runtime/src/main/resources/META-INF/quarkus-extension.yaml index df9380b2a664d..163f70c3e2511 100644 --- a/extensions/container-image/container-image-docker/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/container-image/container-image-docker/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Container Image Docker" metadata: keywords: @@ -7,4 +8,4 @@ metadata: - "image" categories: - "cloud" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/container-image/container-image-jib/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/container-image/container-image-jib/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 58% rename from extensions/container-image/container-image-jib/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/container-image/container-image-jib/runtime/src/main/resources/META-INF/quarkus-extension.yaml index ceccd532473e8..422db45490d53 100644 --- a/extensions/container-image/container-image-jib/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/container-image/container-image-jib/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Container Image Jib" metadata: keywords: @@ -7,4 +8,4 @@ metadata: - "image" categories: - "cloud" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/container-image/container-image-openshift/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/container-image/container-image-openshift/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 60% rename from extensions/container-image/container-image-openshift/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/container-image/container-image-openshift/runtime/src/main/resources/META-INF/quarkus-extension.yaml index b68bef7b3ee46..5f6b78609781c 100644 --- a/extensions/container-image/container-image-openshift/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/container-image/container-image-openshift/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Container Image OpenShift" metadata: keywords: @@ -7,4 +8,4 @@ metadata: - "image" categories: - "cloud" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/container-image/container-image-s2i/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/container-image/container-image-s2i/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 58% rename from extensions/container-image/container-image-s2i/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/container-image/container-image-s2i/runtime/src/main/resources/META-INF/quarkus-extension.yaml index df908dd935878..46f5567aa08d0 100644 --- a/extensions/container-image/container-image-s2i/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/container-image/container-image-s2i/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Container Image S2I" metadata: keywords: @@ -7,4 +8,4 @@ metadata: - "image" categories: - "cloud" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/container-image/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/container-image/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 60% rename from extensions/container-image/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/container-image/runtime/src/main/resources/META-INF/quarkus-extension.yaml index e4c9d0cbc8ebd..23e17716ff097 100644 --- a/extensions/container-image/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/container-image/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Container Image" metadata: keywords: @@ -7,4 +8,4 @@ metadata: categories: - "cloud" status: "preview" - unlisted: true + unlisted: true \ No newline at end of file diff --git a/extensions/datasource/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/datasource/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 58% rename from extensions/datasource/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/datasource/runtime/src/main/resources/META-INF/quarkus-extension.yaml index cd86c341468d3..851e7cc5c31a7 100644 --- a/extensions/datasource/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/datasource/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Datasource configuration" metadata: keywords: @@ -6,4 +7,4 @@ metadata: categories: - "data" status: "stable" - unlisted: true + unlisted: true \ No newline at end of file diff --git a/extensions/elasticsearch-rest-client-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/elasticsearch-rest-client-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 58% rename from extensions/elasticsearch-rest-client-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/elasticsearch-rest-client-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml index aab0fe0dbc7ce..a2ace267f4663 100644 --- a/extensions/elasticsearch-rest-client-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/elasticsearch-rest-client-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Elasticsearch REST Client Common" metadata: keywords: @@ -6,4 +7,4 @@ metadata: categories: - "data" status: "stable" - unlisted: "true" + unlisted: "true" \ No newline at end of file diff --git a/extensions/elasticsearch-rest-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/elasticsearch-rest-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 67% rename from extensions/elasticsearch-rest-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/elasticsearch-rest-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 3ffbcee954d7a..294e0c5781d69 100644 --- a/extensions/elasticsearch-rest-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/elasticsearch-rest-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Elasticsearch REST client" metadata: keywords: @@ -8,4 +9,4 @@ metadata: guide: "https://quarkus.io/guides/elasticsearch" categories: - "data" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/elasticsearch-rest-high-level-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/elasticsearch-rest-high-level-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 68% rename from extensions/elasticsearch-rest-high-level-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/elasticsearch-rest-high-level-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 444655a28472e..8f3cabf22b9c6 100644 --- a/extensions/elasticsearch-rest-high-level-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/elasticsearch-rest-high-level-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Elasticsearch REST High Level Client" metadata: keywords: @@ -8,4 +9,4 @@ metadata: guide: "https://quarkus.io/guides/elasticsearch" categories: - "data" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/elytron-security-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/elytron-security-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 57% rename from extensions/elytron-security-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/elytron-security-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 97696455e3850..754fdae678ce4 100644 --- a/extensions/elytron-security-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/elytron-security-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Elytron Security Common" metadata: keywords: @@ -6,4 +7,4 @@ metadata: categories: - "security" stable: "true" - unlisted: "true" + unlisted: "true" \ No newline at end of file diff --git a/extensions/elytron-security-jdbc/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/elytron-security-jdbc/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 64% rename from extensions/elytron-security-jdbc/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/elytron-security-jdbc/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 2b83f2b121e7e..71e72cf777936 100644 --- a/extensions/elytron-security-jdbc/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/elytron-security-jdbc/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Elytron Security JDBC" metadata: keywords: @@ -7,4 +8,4 @@ metadata: guide: "https://quarkus.io/guides/security-jdbc" categories: - "security" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/elytron-security-ldap/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/elytron-security-ldap/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 65% rename from extensions/elytron-security-ldap/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/elytron-security-ldap/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 4fc9dcd772342..910b2c4092f09 100644 --- a/extensions/elytron-security-ldap/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/elytron-security-ldap/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Elytron Security LDAP Realm" metadata: keywords: @@ -7,4 +8,4 @@ metadata: guide: "https://quarkus.io/guides/security-ldap" categories: - "security" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/elytron-security-oauth2/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/elytron-security-oauth2/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 65% rename from extensions/elytron-security-oauth2/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/elytron-security-oauth2/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 469b9afae21fd..a8d3846d17113 100644 --- a/extensions/elytron-security-oauth2/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/elytron-security-oauth2/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Elytron Security OAuth 2.0" metadata: keywords: @@ -7,4 +8,4 @@ metadata: categories: - "security" guide: "https://quarkus.io/guides/security-oauth2" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/elytron-security-properties-file/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/elytron-security-properties-file/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 51% rename from extensions/elytron-security-properties-file/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/elytron-security-properties-file/runtime/src/main/resources/META-INF/quarkus-extension.yaml index ecef8086b09ec..54699626898e4 100644 --- a/extensions/elytron-security-properties-file/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/elytron-security-properties-file/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Elytron Security Properties File" metadata: keywords: @@ -6,4 +7,4 @@ metadata: categories: - "security" status: "stable" - guide: "https://quarkus.io/guides/security-properties" + guide: "https://quarkus.io/guides/security-properties" \ No newline at end of file diff --git a/extensions/elytron-security/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/elytron-security/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 56% rename from extensions/elytron-security/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/elytron-security/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 26881aa543850..cecace94c98eb 100644 --- a/extensions/elytron-security/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/elytron-security/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Elytron Security" metadata: keywords: @@ -6,4 +7,4 @@ metadata: categories: - "security" stable: "true" - unlisted: "true" + unlisted: "true" \ No newline at end of file diff --git a/extensions/flyway/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/flyway/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 62% rename from extensions/flyway/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/flyway/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 94f082d7a423f..7d2540a28a610 100644 --- a/extensions/flyway/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/flyway/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Flyway" metadata: keywords: @@ -8,4 +9,4 @@ metadata: guide: "https://quarkus.io/guides/flyway" categories: - "data" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/funqy/funqy-amazon-lambda/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/funqy/funqy-amazon-lambda/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 83% rename from extensions/funqy/funqy-amazon-lambda/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/funqy/funqy-amazon-lambda/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 01365eeacd748..fd91ac70ea124 100644 --- a/extensions/funqy/funqy-amazon-lambda/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/funqy/funqy-amazon-lambda/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "Funqy AWS Lambda Binding" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: keywords: - "funqy" @@ -14,4 +15,4 @@ metadata: name: "funqy-amazon-lambda" kind: "example" languages: "java" - artifact: "io.quarkus:quarkus-project-core-extension-codestarts" + artifact: "io.quarkus:quarkus-project-core-extension-codestarts" \ No newline at end of file diff --git a/extensions/funqy/funqy-google-cloud-functions/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/funqy/funqy-google-cloud-functions/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 86% rename from extensions/funqy/funqy-google-cloud-functions/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/funqy/funqy-google-cloud-functions/runtime/src/main/resources/META-INF/quarkus-extension.yaml index ea4df58c21f01..e0d83dd6d33bf 100644 --- a/extensions/funqy/funqy-google-cloud-functions/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/funqy/funqy-google-cloud-functions/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "Funqy Google Cloud Functions" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: keywords: - "google cloud" diff --git a/extensions/funqy/funqy-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/funqy/funqy-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 80% rename from extensions/funqy/funqy-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/funqy/funqy-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 74f01f7f2cee7..2deefead5317e 100644 --- a/extensions/funqy/funqy-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/funqy/funqy-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "Funqy HTTP Binding" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: keywords: - "funqy" @@ -11,4 +12,4 @@ metadata: codestart: name: "funqy-http" languages: "java" - artifact: "io.quarkus:quarkus-project-core-extension-codestarts" + artifact: "io.quarkus:quarkus-project-core-extension-codestarts" \ No newline at end of file diff --git a/extensions/funqy/funqy-knative-events/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/funqy/funqy-knative-events/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 83% rename from extensions/funqy/funqy-knative-events/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/funqy/funqy-knative-events/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 3b84bf50b9921..4cf57d28407ab 100644 --- a/extensions/funqy/funqy-knative-events/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/funqy/funqy-knative-events/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "Funqy Knative Events Binding" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: keywords: - "knative" @@ -13,4 +14,4 @@ metadata: name: "funqy-knative-events" kind: "example" languages: "java" - artifact: "io.quarkus:quarkus-project-core-extension-codestarts" + artifact: "io.quarkus:quarkus-project-core-extension-codestarts" \ No newline at end of file diff --git a/extensions/funqy/funqy-server-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/funqy/funqy-server-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml new file mode 100644 index 0000000000000..a3c9856d68f1c --- /dev/null +++ b/extensions/funqy/funqy-server-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -0,0 +1,5 @@ +--- +artifact: ${project.groupId}:${project.artifactId}:${project.version} +name: "Funqy Server Common" +metadata: + unlisted: true \ No newline at end of file diff --git a/extensions/funqy/funqy-server-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/funqy/funqy-server-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template deleted file mode 100644 index b93ae46bcb67b..0000000000000 --- a/extensions/funqy/funqy-server-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ /dev/null @@ -1,4 +0,0 @@ ---- -name: "Funqy Server Common" -metadata: - unlisted: true diff --git a/extensions/google-cloud-functions-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/google-cloud-functions-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 83% rename from extensions/google-cloud-functions-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/google-cloud-functions-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 5ee244dc0c75c..515fa7715954d 100644 --- a/extensions/google-cloud-functions-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/google-cloud-functions-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "Google Cloud Functions HTTP" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: keywords: - "google cloud" @@ -14,4 +15,4 @@ metadata: name: "google-cloud-functions-http" kind: "example" languages: "java" - artifact: "io.quarkus:quarkus-project-core-extension-codestarts" + artifact: "io.quarkus:quarkus-project-core-extension-codestarts" \ No newline at end of file diff --git a/extensions/google-cloud-functions/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/google-cloud-functions/runtime/src/main/resources/META-INF/quarkus-extension.yaml old mode 100755 new mode 100644 similarity index 82% rename from extensions/google-cloud-functions/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/google-cloud-functions/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 36e37f1ea0c7d..638cb251458a6 --- a/extensions/google-cloud-functions/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/google-cloud-functions/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "Google Cloud Functions" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: keywords: - "google cloud" @@ -13,4 +14,4 @@ metadata: name: "google-cloud-functions" kind: "example" languages: "java" - artifact: "io.quarkus:quarkus-project-core-extension-codestarts" + artifact: "io.quarkus:quarkus-project-core-extension-codestarts" \ No newline at end of file diff --git a/extensions/grpc-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/grpc-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 62% rename from extensions/grpc-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/grpc-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml index fd36e68616d82..0ae1150607624 100644 --- a/extensions/grpc-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/grpc-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "gRPC Common" metadata: keywords: @@ -8,4 +9,4 @@ metadata: - "serialization" - "reactive" status: "experimental" - unlisted: "true" + unlisted: "true" \ No newline at end of file diff --git a/extensions/grpc/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/grpc/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 55% rename from extensions/grpc/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/grpc/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 43a010c57b5e1..f5b240fd22aa9 100644 --- a/extensions/grpc/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/grpc/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "gRPC" metadata: keywords: @@ -7,4 +8,4 @@ metadata: - "web" - "serialization" - "reactive" - status: "experimental" + status: "experimental" \ No newline at end of file diff --git a/extensions/hibernate-envers/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/hibernate-envers/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 68% rename from extensions/hibernate-envers/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/hibernate-envers/runtime/src/main/resources/META-INF/quarkus-extension.yaml index f0685953e2d1c..e6a0a5e4250df 100644 --- a/extensions/hibernate-envers/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/hibernate-envers/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Hibernate Envers" metadata: short-name: "Envers" @@ -9,4 +10,4 @@ metadata: guide: "https://quarkus.io/guides/hibernate-orm#envers" categories: - "data" - status: "experimental" + status: "experimental" \ No newline at end of file diff --git a/extensions/hibernate-orm/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/hibernate-orm/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 68% rename from extensions/hibernate-orm/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/hibernate-orm/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 51b9c0da12dc4..b8b9bf920d254 100644 --- a/extensions/hibernate-orm/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/hibernate-orm/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Hibernate ORM" metadata: short-name: "JPA" @@ -9,4 +10,4 @@ metadata: guide: "https://quarkus.io/guides/hibernate-orm" categories: - "data" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/hibernate-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/hibernate-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 64% rename from extensions/hibernate-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/hibernate-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 0778b7ced42ad..5bc89bca41722 100644 --- a/extensions/hibernate-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/hibernate-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Hibernate Reactive" metadata: keywords: @@ -9,4 +10,4 @@ metadata: categories: - "data" - "reactive" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 80% rename from extensions/hibernate-search-orm-elasticsearch/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/hibernate-search-orm-elasticsearch/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 961e0a436f6f4..a48d10f8c5a14 100644 --- a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Hibernate Search + Elasticsearch" metadata: keywords: @@ -14,4 +15,4 @@ metadata: guide: "https://quarkus.io/guides/hibernate-search-orm-elasticsearch" categories: - "data" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/hibernate-validator/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/hibernate-validator/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 72% rename from extensions/hibernate-validator/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/hibernate-validator/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 672d948475385..fd0b545a4557a 100644 --- a/extensions/hibernate-validator/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/hibernate-validator/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Hibernate Validator" metadata: short-name: "bean validation" @@ -10,4 +11,4 @@ metadata: categories: - "web" - "data" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/infinispan-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/infinispan-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 69% rename from extensions/infinispan-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/infinispan-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 960b40e346b16..ad128cf11b913 100644 --- a/extensions/infinispan-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/infinispan-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Infinispan Client" metadata: keywords: @@ -8,4 +9,4 @@ metadata: guide: "https://quarkus.io/guides/infinispan-client" categories: - "data" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 53% rename from extensions/jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 087f4ecae61bf..794681c744ecc 100644 --- a/extensions/jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Jackson" metadata: keywords: @@ -6,4 +7,4 @@ metadata: - "json" categories: - "serialization" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/jaeger/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/jaeger/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 63% rename from extensions/jaeger/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/jaeger/runtime/src/main/resources/META-INF/quarkus-extension.yaml index fbdf53bdcf61f..6fddfd040ba04 100644 --- a/extensions/jaeger/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/jaeger/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Jaeger" metadata: keywords: @@ -8,4 +9,4 @@ metadata: categories: - "observability" unlisted: true - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 59% rename from extensions/jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml index e782277cd7eb6..67783f1b2fbea 100644 --- a/extensions/jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "JAXB" metadata: keywords: @@ -8,4 +9,4 @@ metadata: - "xml" categories: - "serialization" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/jaxp/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/jaxp/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 56% rename from extensions/jaxp/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/jaxp/runtime/src/main/resources/META-INF/quarkus-extension.yaml index f92a9c73b94b6..c840b33fdb573 100644 --- a/extensions/jaxp/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/jaxp/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "JAXP" metadata: keywords: @@ -7,4 +8,4 @@ metadata: categories: - "serialization" status: "stable" - unlisted: true + unlisted: true \ No newline at end of file diff --git a/extensions/jdbc/jdbc-db2/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/jdbc/jdbc-db2/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 56% rename from extensions/jdbc/jdbc-db2/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/jdbc/jdbc-db2/runtime/src/main/resources/META-INF/quarkus-extension.yaml index a3fa12e7954cd..54b6fdc487107 100644 --- a/extensions/jdbc/jdbc-db2/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/jdbc/jdbc-db2/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "JDBC Driver - DB2" metadata: keywords: @@ -6,4 +7,4 @@ metadata: - "jdbc" - "db2" categories: - - "data" + - "data" \ No newline at end of file diff --git a/extensions/jdbc/jdbc-derby/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/jdbc/jdbc-derby/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 57% rename from extensions/jdbc/jdbc-derby/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/jdbc/jdbc-derby/runtime/src/main/resources/META-INF/quarkus-extension.yaml index d62899a97413e..c197ac8d0687d 100644 --- a/extensions/jdbc/jdbc-derby/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/jdbc/jdbc-derby/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "JDBC Driver - Derby" metadata: keywords: @@ -7,4 +8,4 @@ metadata: - "derby" categories: - "data" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/jdbc/jdbc-h2/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/jdbc/jdbc-h2/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 64% rename from extensions/jdbc/jdbc-h2/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/jdbc/jdbc-h2/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 344d59830fcd8..63fabedc3fdd2 100644 --- a/extensions/jdbc/jdbc-h2/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/jdbc/jdbc-h2/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "JDBC Driver - H2" metadata: keywords: diff --git a/extensions/jdbc/jdbc-mariadb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/jdbc/jdbc-mariadb/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 58% rename from extensions/jdbc/jdbc-mariadb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/jdbc/jdbc-mariadb/runtime/src/main/resources/META-INF/quarkus-extension.yaml index f89b746f99c4d..22a1bca61755a 100644 --- a/extensions/jdbc/jdbc-mariadb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/jdbc/jdbc-mariadb/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "JDBC Driver - MariaDB" metadata: keywords: @@ -7,4 +8,4 @@ metadata: - "mariadb" categories: - "data" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/jdbc/jdbc-mssql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/jdbc/jdbc-mssql/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 63% rename from extensions/jdbc/jdbc-mssql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/jdbc/jdbc-mssql/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 0864f5ad0aba0..d3ddcb4dfdabb 100644 --- a/extensions/jdbc/jdbc-mssql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/jdbc/jdbc-mssql/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "JDBC Driver - Microsoft SQL Server" metadata: keywords: @@ -8,4 +9,4 @@ metadata: - "sql-server" categories: - "data" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/jdbc/jdbc-mysql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/jdbc/jdbc-mysql/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 57% rename from extensions/jdbc/jdbc-mysql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/jdbc/jdbc-mysql/runtime/src/main/resources/META-INF/quarkus-extension.yaml index bb2a3c6d7d038..16430ba331b50 100644 --- a/extensions/jdbc/jdbc-mysql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/jdbc/jdbc-mysql/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "JDBC Driver - MySQL" metadata: keywords: @@ -7,4 +8,4 @@ metadata: - "mysql" categories: - "data" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/jdbc/jdbc-oracle/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/jdbc/jdbc-oracle/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 66% rename from extensions/jdbc/jdbc-oracle/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/jdbc/jdbc-oracle/runtime/src/main/resources/META-INF/quarkus-extension.yaml index cec79addab8d9..3c12a397a6589 100644 --- a/extensions/jdbc/jdbc-oracle/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/jdbc/jdbc-oracle/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "JDBC Driver - Oracle" metadata: keywords: diff --git a/extensions/jdbc/jdbc-postgresql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/jdbc/jdbc-postgresql/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 60% rename from extensions/jdbc/jdbc-postgresql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/jdbc/jdbc-postgresql/runtime/src/main/resources/META-INF/quarkus-extension.yaml index c4d9ae1b87b09..71188628bfaec 100644 --- a/extensions/jdbc/jdbc-postgresql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/jdbc/jdbc-postgresql/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "JDBC Driver - PostgreSQL" metadata: keywords: @@ -6,4 +7,4 @@ metadata: - "jdbc" - "postgresql" categories: - - "data" + - "data" \ No newline at end of file diff --git a/extensions/jgit/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/jgit/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 58% rename from extensions/jgit/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/jgit/runtime/src/main/resources/META-INF/quarkus-extension.yaml index b4a90c99d7efe..5907f7ba2be1a 100644 --- a/extensions/jgit/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/jgit/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "JGit" metadata: keywords: @@ -6,4 +7,4 @@ metadata: categories: - "miscellaneous" guide: "https://quarkus.io/guides/jgit" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/jsch/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/jsch/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 66% rename from extensions/jsch/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/jsch/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 8063b678d7ca1..b18f9df2beb90 100644 --- a/extensions/jsch/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/jsch/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "JSch" metadata: keywords: diff --git a/extensions/jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 64% rename from extensions/jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 23dde18cef90d..cbbb59a634290 100644 --- a/extensions/jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "JSON-B" metadata: keywords: @@ -8,4 +9,4 @@ metadata: guide: "https://quarkus.io/guides/rest-json" categories: - "serialization" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/jsonp/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/jsonp/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 55% rename from extensions/jsonp/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/jsonp/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 8c41e12e552ae..ab01233028665 100644 --- a/extensions/jsonp/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/jsonp/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "JSON-P" metadata: keywords: @@ -7,4 +8,4 @@ metadata: - "json" categories: - "serialization" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/kafka-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/kafka-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 61% rename from extensions/kafka-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/kafka-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 61dbb28d73c4b..79a81288b3d84 100644 --- a/extensions/kafka-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/kafka-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Apache Kafka Client" metadata: keywords: @@ -6,4 +7,4 @@ metadata: guide: "https://quarkus.io/guides/kafka" categories: - "messaging" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/kafka-streams/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/kafka-streams/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 65% rename from extensions/kafka-streams/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/kafka-streams/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 6fecd0964c7bb..cee32b38a176c 100644 --- a/extensions/kafka-streams/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/kafka-streams/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Apache Kafka Streams" metadata: keywords: @@ -7,4 +8,4 @@ metadata: categories: - "messaging" guide: "https://quarkus.io/guides/kafka-streams" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/keycloak-admin-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/keycloak-admin-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 64% rename from extensions/keycloak-admin-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/keycloak-admin-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml index fa439f487f19a..8ca9fe13e7d1c 100644 --- a/extensions/keycloak-admin-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/keycloak-admin-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Keycloak Admin Client" metadata: keywords: @@ -8,4 +9,4 @@ metadata: - "openid-connect" categories: - "security" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/keycloak-authorization/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/keycloak-authorization/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 78% rename from extensions/keycloak-authorization/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/keycloak-authorization/runtime/src/main/resources/META-INF/quarkus-extension.yaml index ea6e56e7b6b17..cdfccc7471057 100644 --- a/extensions/keycloak-authorization/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/keycloak-authorization/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Keycloak Authorization" metadata: keywords: @@ -12,4 +13,4 @@ metadata: guide: "https://quarkus.io/guides/security-keycloak-authorization" categories: - "security" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 77% rename from extensions/kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 04d3b29899167..4744302d1280c 100644 --- a/extensions/kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "Kotlin" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: keywords: - "kotlin" @@ -9,4 +10,4 @@ metadata: codestart: name: "kotlin" kind: "core" - artifact: "io.quarkus:quarkus-project-core-extension-codestarts" + artifact: "io.quarkus:quarkus-project-core-extension-codestarts" \ No newline at end of file diff --git a/extensions/kubernetes-client/runtime-internal/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/kubernetes-client/runtime-internal/src/main/resources/META-INF/quarkus-extension.yaml similarity index 61% rename from extensions/kubernetes-client/runtime-internal/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/kubernetes-client/runtime-internal/src/main/resources/META-INF/quarkus-extension.yaml index 4ea25b879def3..238459602f709 100644 --- a/extensions/kubernetes-client/runtime-internal/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/kubernetes-client/runtime-internal/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Kubernetes Client Internal" metadata: keywords: @@ -6,4 +7,4 @@ metadata: categories: - "cloud" status: "stable" - unlisted: true + unlisted: true \ No newline at end of file diff --git a/extensions/kubernetes-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/kubernetes-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 71% rename from extensions/kubernetes-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/kubernetes-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 836d9fd165465..f401529dbe48e 100644 --- a/extensions/kubernetes-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/kubernetes-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Kubernetes Client" metadata: keywords: diff --git a/extensions/kubernetes-config/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/kubernetes-config/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 63% rename from extensions/kubernetes-config/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/kubernetes-config/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 82d9f52268c24..900df03184fc8 100644 --- a/extensions/kubernetes-config/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/kubernetes-config/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Kubernetes Config" metadata: keywords: @@ -6,4 +7,4 @@ metadata: guide: "https://quarkus.io/guides/kubernetes-config" categories: - "cloud" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/kubernetes-service-binding/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/kubernetes-service-binding/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 57% rename from extensions/kubernetes-service-binding/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/kubernetes-service-binding/runtime/src/main/resources/META-INF/quarkus-extension.yaml index ec28e4874c408..0ab9aea62969e 100644 --- a/extensions/kubernetes-service-binding/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/kubernetes-service-binding/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,8 +1,9 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Kubernetes Service Binding" metadata: keywords: - "kubernetes-service-binding" categories: - "cloud" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/kubernetes/minikube/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/kubernetes/minikube/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 62% rename from extensions/kubernetes/minikube/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/kubernetes/minikube/runtime/src/main/resources/META-INF/quarkus-extension.yaml index bd68dfc55c5fa..5fd6011b26148 100644 --- a/extensions/kubernetes/minikube/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/kubernetes/minikube/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Minikube" metadata: keywords: @@ -7,4 +8,4 @@ metadata: guide: "https://quarkus.io/guides/kubernetes" categories: - "cloud" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/kubernetes/openshift/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/kubernetes/openshift/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 63% rename from extensions/kubernetes/openshift/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/kubernetes/openshift/runtime/src/main/resources/META-INF/quarkus-extension.yaml index d79128eeceb24..b7309bf7f9670 100644 --- a/extensions/kubernetes/openshift/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/kubernetes/openshift/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "OpenShift" metadata: keywords: @@ -7,4 +8,4 @@ metadata: guide: "https://quarkus.io/guides/openshift" categories: - "cloud" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/kubernetes/vanilla/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/kubernetes/vanilla/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 60% rename from extensions/kubernetes/vanilla/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/kubernetes/vanilla/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 11232fb051d40..830a133d189c9 100644 --- a/extensions/kubernetes/vanilla/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/kubernetes/vanilla/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Kubernetes" metadata: keywords: @@ -6,4 +7,4 @@ metadata: guide: "https://quarkus.io/guides/kubernetes" categories: - "cloud" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/liquibase/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/liquibase/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 63% rename from extensions/liquibase/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/liquibase/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 333cb79ec9c68..b2a18b78cdbeb 100644 --- a/extensions/liquibase/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/liquibase/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Liquibase" metadata: keywords: @@ -8,4 +9,4 @@ metadata: guide: "https://quarkus.io/guides/liquibase" categories: - "data" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/logging-gelf/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/logging-gelf/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 66% rename from extensions/logging-gelf/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/logging-gelf/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 36df0f176b177..900ad5b785d2a 100644 --- a/extensions/logging-gelf/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/logging-gelf/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Logging GELF" metadata: keywords: @@ -8,4 +9,4 @@ metadata: guide: "https://quarkus.io/guides/centralized-log-management" categories: - "core" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/logging-json/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/logging-json/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 51% rename from extensions/logging-json/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/logging-json/runtime/src/main/resources/META-INF/quarkus-extension.yaml index b86d2e3b778d7..f91846c78ba44 100644 --- a/extensions/logging-json/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/logging-json/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Logging JSON" metadata: keywords: @@ -8,4 +9,4 @@ metadata: categories: - "core" status: "preview" - guide: "https://quarkus.io/guides/logging#json-logging" + guide: "https://quarkus.io/guides/logging#json-logging" \ No newline at end of file diff --git a/extensions/logging-sentry/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/logging-sentry/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 72% rename from extensions/logging-sentry/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/logging-sentry/runtime/src/main/resources/META-INF/quarkus-extension.yaml index a33c51adf5586..731dab299fe81 100644 --- a/extensions/logging-sentry/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/logging-sentry/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Logging Sentry" metadata: keywords: diff --git a/extensions/mailer/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/mailer/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 61% rename from extensions/mailer/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/mailer/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 71ad33cacf957..0f8e9d3c27be7 100644 --- a/extensions/mailer/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/mailer/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Mailer" metadata: keywords: @@ -7,4 +8,4 @@ metadata: guide: "https://quarkus.io/guides/mailer" categories: - "miscellaneous" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/micrometer-registry-prometheus/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/micrometer-registry-prometheus/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 72% rename from extensions/micrometer-registry-prometheus/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/micrometer-registry-prometheus/runtime/src/main/resources/META-INF/quarkus-extension.yaml index e815b00986e6c..3c999b3ee40b0 100644 --- a/extensions/micrometer-registry-prometheus/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/micrometer-registry-prometheus/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "Micrometer Registry Prometheus" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: keywords: - "micrometer" @@ -9,4 +10,4 @@ metadata: guide: "https://quarkus.io/guides/micrometer-metrics" categories: - "observability" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/micrometer/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/micrometer/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 68% rename from extensions/micrometer/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/micrometer/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 31b9bcdff9018..12a19a6d5133a 100644 --- a/extensions/micrometer/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/micrometer/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "Micrometer metrics" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: keywords: - "micrometer" @@ -8,4 +9,4 @@ metadata: guide: "https://quarkus.io/guides/micrometer" categories: - "observability" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/mongodb-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/mongodb-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 66% rename from extensions/mongodb-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/mongodb-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 98707d319cf4d..e6ad36bd0199f 100644 --- a/extensions/mongodb-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/mongodb-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "MongoDB client" metadata: keywords: @@ -9,4 +10,4 @@ metadata: guide: "https://quarkus.io/guides/mongodb" categories: - "data" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 64% rename from extensions/mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml index c09aa0ebf0aaf..658ebabc08bea 100644 --- a/extensions/mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Mutiny" metadata: keywords: @@ -9,4 +10,4 @@ metadata: - "Reactor" categories: - "reactive" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/narayana-jta/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/narayana-jta/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 73% rename from extensions/narayana-jta/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/narayana-jta/runtime/src/main/resources/META-INF/quarkus-extension.yaml index ba07661770279..27029b1d91df6 100644 --- a/extensions/narayana-jta/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/narayana-jta/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Narayana JTA - Transaction manager" metadata: keywords: @@ -12,4 +13,4 @@ metadata: guide: "https://quarkus.io/guides/transaction" categories: - "data" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/narayana-stm/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/narayana-stm/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 77% rename from extensions/narayana-stm/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/narayana-stm/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 4b75c68699b18..dcd842fe1f4d0 100644 --- a/extensions/narayana-stm/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/narayana-stm/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Narayana STM - Software Transactional Memory" metadata: keywords: @@ -13,4 +14,4 @@ metadata: guide: "https://quarkus.io/guides/software-transactional-memory" categories: - "data" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/neo4j/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/neo4j/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 65% rename from extensions/neo4j/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/neo4j/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 3b7449cbec6d6..d5c6003aa22a9 100644 --- a/extensions/neo4j/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/neo4j/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Neo4j client" metadata: keywords: @@ -9,4 +10,4 @@ metadata: guide: "https://quarkus.io/guides/neo4j" categories: - "data" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/netty/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/netty/runtime/src/main/resources/META-INF/quarkus-extension.yaml new file mode 100644 index 0000000000000..752f39bb99727 --- /dev/null +++ b/extensions/netty/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -0,0 +1,8 @@ +--- +artifact: ${project.groupId}:${project.artifactId}:${project.version} +name: "Netty" +metadata: + categories: + - "web" + status: "stable" + unlisted: true \ No newline at end of file diff --git a/extensions/netty/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/netty/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template deleted file mode 100644 index 24981366cfc15..0000000000000 --- a/extensions/netty/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ /dev/null @@ -1,7 +0,0 @@ ---- -name: "Netty" -metadata: - categories: - - "web" - status: "stable" - unlisted: true diff --git a/extensions/oidc-client-filter/deployment/pom.xml b/extensions/oidc-client-filter/deployment/pom.xml index ca5e2ec5dfca7..53288fad78699 100644 --- a/extensions/oidc-client-filter/deployment/pom.xml +++ b/extensions/oidc-client-filter/deployment/pom.xml @@ -49,12 +49,12 @@ io.quarkus - quarkus-oidc + quarkus-oidc-deployment test io.quarkus - quarkus-resteasy + quarkus-resteasy-deployment test diff --git a/extensions/oidc-client-filter/pom.xml b/extensions/oidc-client-filter/pom.xml index 85cafdf27bbef..fb13119f20198 100644 --- a/extensions/oidc-client-filter/pom.xml +++ b/extensions/oidc-client-filter/pom.xml @@ -3,10 +3,10 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> - quarkus-build-parent + quarkus-extensions-parent io.quarkus 999-SNAPSHOT - ../../build-parent/pom.xml + ../pom.xml 4.0.0 diff --git a/extensions/oidc-client-filter/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/oidc-client-filter/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 73% rename from extensions/oidc-client-filter/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/oidc-client-filter/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 66db08ec05c48..48d29eeda4cee 100644 --- a/extensions/oidc-client-filter/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/oidc-client-filter/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "OpenID Connect Client Filter" metadata: keywords: @@ -10,4 +11,4 @@ metadata: guide: "https://quarkus.io/guides/security-openid-connect-client" categories: - "security" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/oidc-client-reactive-filter/pom.xml b/extensions/oidc-client-reactive-filter/pom.xml index 47a0c88fd8aed..b729a6d6c80be 100644 --- a/extensions/oidc-client-reactive-filter/pom.xml +++ b/extensions/oidc-client-reactive-filter/pom.xml @@ -3,10 +3,10 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> - quarkus-build-parent + quarkus-extensions-parent io.quarkus 999-SNAPSHOT - ../../build-parent/pom.xml + ../pom.xml 4.0.0 diff --git a/extensions/oidc-client-reactive-filter/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/oidc-client-reactive-filter/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 76% rename from extensions/oidc-client-reactive-filter/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/oidc-client-reactive-filter/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 321b51604f703..0827687fc817d 100644 --- a/extensions/oidc-client-reactive-filter/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/oidc-client-reactive-filter/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "OpenID Connect Client Filter Reactive" metadata: keywords: @@ -11,4 +12,4 @@ metadata: guide: "https://quarkus.io/guides/security-openid-connect-client" categories: - "security" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/oidc-client/deployment/pom.xml b/extensions/oidc-client/deployment/pom.xml index 971cb04347051..02079ed6339fe 100644 --- a/extensions/oidc-client/deployment/pom.xml +++ b/extensions/oidc-client/deployment/pom.xml @@ -66,17 +66,17 @@ io.quarkus - quarkus-resteasy-mutiny + quarkus-resteasy-mutiny-deployment test io.quarkus - quarkus-oidc + quarkus-oidc-deployment test io.quarkus - quarkus-rest-client + quarkus-rest-client-deployment test diff --git a/extensions/oidc-client/pom.xml b/extensions/oidc-client/pom.xml index 8a02c42688648..58792529ef294 100644 --- a/extensions/oidc-client/pom.xml +++ b/extensions/oidc-client/pom.xml @@ -3,10 +3,10 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> - quarkus-build-parent + quarkus-extensions-parent io.quarkus 999-SNAPSHOT - ../../build-parent/pom.xml + ../pom.xml 4.0.0 diff --git a/extensions/oidc-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/oidc-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 70% rename from extensions/oidc-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/oidc-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 740b361072ae0..a09103cec0de7 100644 --- a/extensions/oidc-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/oidc-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "OpenID Connect Client" metadata: keywords: @@ -9,4 +10,4 @@ metadata: guide: "https://quarkus.io/guides/security-openid-connect-client" categories: - "security" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/oidc-common/pom.xml b/extensions/oidc-common/pom.xml index 93ec3a981d41d..2b9a2d6ce5303 100644 --- a/extensions/oidc-common/pom.xml +++ b/extensions/oidc-common/pom.xml @@ -3,10 +3,10 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> - quarkus-build-parent + quarkus-extensions-parent io.quarkus 999-SNAPSHOT - ../../build-parent/pom.xml + ../pom.xml 4.0.0 diff --git a/extensions/oidc-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/oidc-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 63% rename from extensions/oidc-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/oidc-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml index af3f6c46792f0..5a7553b879a74 100644 --- a/extensions/oidc-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/oidc-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "OpenID Connect Common" metadata: keywords: @@ -8,4 +9,4 @@ metadata: categories: - "security" status: "preview" - unlisted: true + unlisted: true \ No newline at end of file diff --git a/extensions/oidc-token-propagation/pom.xml b/extensions/oidc-token-propagation/pom.xml index 998b2b62ee3b0..14168cda845b1 100644 --- a/extensions/oidc-token-propagation/pom.xml +++ b/extensions/oidc-token-propagation/pom.xml @@ -3,10 +3,10 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> - quarkus-build-parent + quarkus-extensions-parent io.quarkus 999-SNAPSHOT - ../../build-parent/pom.xml + ../pom.xml 4.0.0 diff --git a/extensions/oidc-token-propagation/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/oidc-token-propagation/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 74% rename from extensions/oidc-token-propagation/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/oidc-token-propagation/runtime/src/main/resources/META-INF/quarkus-extension.yaml index f66fae8a8a4e7..27a5f5da4e145 100644 --- a/extensions/oidc-token-propagation/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/oidc-token-propagation/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "OpenID Connect Token Propagation" metadata: keywords: @@ -10,4 +11,4 @@ metadata: guide: "https://quarkus.io/guides/security-openid-connect-client" categories: - "security" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/oidc/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/oidc/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 67% rename from extensions/oidc/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/oidc/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 61e35a98dd37a..d6ab32f583c3b 100644 --- a/extensions/oidc/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/oidc/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "OpenID Connect" metadata: keywords: @@ -8,4 +9,4 @@ metadata: guide: "https://quarkus.io/guides/security-openid-connect" categories: - "security" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/openshift-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/openshift-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 65% rename from extensions/openshift-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/openshift-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 1d0e73be74e26..a4815fcbbbf23 100644 --- a/extensions/openshift-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/openshift-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "OpenShift Client" metadata: keywords: @@ -7,4 +8,4 @@ metadata: guide: https://quarkus.io/guides/kubernetes-client categories: - "cloud" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/opentelemetry-exporter-jaeger/pom.xml b/extensions/opentelemetry-exporter-jaeger/pom.xml index cf08e24c5b087..65eeab453ab1b 100644 --- a/extensions/opentelemetry-exporter-jaeger/pom.xml +++ b/extensions/opentelemetry-exporter-jaeger/pom.xml @@ -3,10 +3,10 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> - quarkus-build-parent + quarkus-extensions-parent io.quarkus 999-SNAPSHOT - ../../build-parent/pom.xml + ../pom.xml 4.0.0 diff --git a/extensions/opentelemetry-exporter-jaeger/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/opentelemetry-exporter-jaeger/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 74% rename from extensions/opentelemetry-exporter-jaeger/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/opentelemetry-exporter-jaeger/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 9ae15434a531f..c3f159836c06a 100644 --- a/extensions/opentelemetry-exporter-jaeger/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/opentelemetry-exporter-jaeger/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "OpenTelemetry exporter: Jaeger" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: keywords: - "opentelemetry" @@ -9,4 +10,4 @@ metadata: guide: "https://quarkus.io/guides/opentelemetry" categories: - "observability" - status: "experimental" + status: "experimental" \ No newline at end of file diff --git a/extensions/opentelemetry/pom.xml b/extensions/opentelemetry/pom.xml index 2b07fb20908fb..2097eb3a0dcd1 100644 --- a/extensions/opentelemetry/pom.xml +++ b/extensions/opentelemetry/pom.xml @@ -3,10 +3,10 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> - quarkus-build-parent + quarkus-extensions-parent io.quarkus 999-SNAPSHOT - ../../build-parent/pom.xml + ../pom.xml 4.0.0 diff --git a/extensions/opentelemetry/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/opentelemetry/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 70% rename from extensions/opentelemetry/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/opentelemetry/runtime/src/main/resources/META-INF/quarkus-extension.yaml index aa4a09111bce7..923169ff93bcb 100644 --- a/extensions/opentelemetry/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/opentelemetry/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "OpenTelemetry" metadata: keywords: @@ -9,4 +10,4 @@ metadata: guide: "https://quarkus.io/guides/opentelemetry" categories: - "observability" - status: "experimental" + status: "experimental" \ No newline at end of file diff --git a/extensions/panache/hibernate-orm-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/panache/hibernate-orm-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 74% rename from extensions/panache/hibernate-orm-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/panache/hibernate-orm-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml index e05490e96ac49..77ffb88f5c816 100644 --- a/extensions/panache/hibernate-orm-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/panache/hibernate-orm-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Hibernate ORM with Panache Common module" metadata: keywords: @@ -10,4 +11,3 @@ metadata: - "data" status: "stable" unlisted: true - diff --git a/extensions/panache/hibernate-orm-panache-kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/panache/hibernate-orm-panache-kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 72% rename from extensions/panache/hibernate-orm-panache-kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/panache/hibernate-orm-panache-kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 38e99648e8dc7..647d1e46bf95f 100644 --- a/extensions/panache/hibernate-orm-panache-kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/panache/hibernate-orm-panache-kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Hibernate ORM with Panache and Kotlin" metadata: keywords: @@ -10,4 +11,4 @@ metadata: guide: "https://quarkus.io/guides/hibernate-orm-panache-kotlin" categories: - "data" - status: "experimental" + status: "experimental" \ No newline at end of file diff --git a/extensions/panache/hibernate-orm-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/panache/hibernate-orm-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 70% rename from extensions/panache/hibernate-orm-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/panache/hibernate-orm-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml index f541c03718457..2593028610147 100644 --- a/extensions/panache/hibernate-orm-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/panache/hibernate-orm-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Hibernate ORM with Panache" metadata: keywords: @@ -9,4 +10,4 @@ metadata: guide: "https://quarkus.io/guides/hibernate-orm-panache" categories: - "data" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/panache/hibernate-orm-rest-data-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/panache/hibernate-orm-rest-data-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 74% rename from extensions/panache/hibernate-orm-rest-data-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/panache/hibernate-orm-rest-data-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 362533898aafc..2f07493e20daf 100644 --- a/extensions/panache/hibernate-orm-rest-data-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/panache/hibernate-orm-rest-data-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "REST resources for Hibernate ORM with Panache" metadata: keywords: @@ -13,4 +14,4 @@ metadata: categories: - "data" - "web" - status: "experimental" + status: "experimental" \ No newline at end of file diff --git a/extensions/panache/hibernate-reactive-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/panache/hibernate-reactive-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 75% rename from extensions/panache/hibernate-reactive-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/panache/hibernate-reactive-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 5f949f726dcd0..740a4dca1a8c0 100644 --- a/extensions/panache/hibernate-reactive-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/panache/hibernate-reactive-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Hibernate Reactive with Panache Common module" metadata: keywords: @@ -10,4 +11,3 @@ metadata: - "data" status: "stable" unlisted: true - diff --git a/extensions/panache/hibernate-reactive-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/panache/hibernate-reactive-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 64% rename from extensions/panache/hibernate-reactive-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/panache/hibernate-reactive-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 4c6d1666aff31..82a55ed7be4ed 100644 --- a/extensions/panache/hibernate-reactive-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/panache/hibernate-reactive-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Hibernate Reactive with Panache" metadata: keywords: @@ -8,4 +9,4 @@ metadata: - "jpa" categories: - "data" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/panache/mongodb-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/panache/mongodb-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml new file mode 100644 index 0000000000000..c5950d244ee2d --- /dev/null +++ b/extensions/panache/mongodb-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -0,0 +1,5 @@ +--- +artifact: ${project.groupId}:${project.artifactId}:${project.version} +name: "MongoDB Panache Common module" +metadata: + unlisted: true \ No newline at end of file diff --git a/extensions/panache/mongodb-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/panache/mongodb-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template deleted file mode 100644 index 659c8b8f067aa..0000000000000 --- a/extensions/panache/mongodb-panache-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ /dev/null @@ -1,4 +0,0 @@ ---- -name: "MongoDB Panache Common module" -metadata: - unlisted: true diff --git a/extensions/panache/mongodb-panache-kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/panache/mongodb-panache-kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 64% rename from extensions/panache/mongodb-panache-kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/panache/mongodb-panache-kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 7588222abb56a..b82ac1d534856 100644 --- a/extensions/panache/mongodb-panache-kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/panache/mongodb-panache-kotlin/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "MongoDB with Panache for Kotlin" metadata: keywords: @@ -8,4 +9,4 @@ metadata: - "kotlin" categories: - "data" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/panache/mongodb-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/panache/mongodb-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 69% rename from extensions/panache/mongodb-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/panache/mongodb-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 5b6b9e0d910d7..d3d076ace6ebd 100644 --- a/extensions/panache/mongodb-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/panache/mongodb-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "MongoDB with Panache" metadata: keywords: @@ -10,4 +11,4 @@ metadata: guide: "https://quarkus.io/guides/mongodb-panache" categories: - "data" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/panache/mongodb-rest-data-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/panache/mongodb-rest-data-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 72% rename from extensions/panache/mongodb-rest-data-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/panache/mongodb-rest-data-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml index aaf2d62245861..6de36e197e5a4 100644 --- a/extensions/panache/mongodb-rest-data-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/panache/mongodb-rest-data-panache/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "REST resources for MongoDB with Panache" metadata: keywords: @@ -12,4 +13,4 @@ metadata: categories: - "data" - "web" - status: "experimental" + status: "experimental" \ No newline at end of file diff --git a/extensions/panache/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/panache/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 76% rename from extensions/panache/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/panache/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 22fb2756cf9cd..baeb269fec9e5 100644 --- a/extensions/panache/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/panache/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: Quarkus Resteasy Reactive Problem +artifact: ${project.groupId}:${project.artifactId}:${project.version} #description: Quarkus Resteasy Reactive Problem ... metadata: # keywords: diff --git a/extensions/picocli/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/picocli/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 81% rename from extensions/picocli/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/picocli/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 26377d23af48c..3ced9ac54767e 100644 --- a/extensions/picocli/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/picocli/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "Picocli" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: keywords: - "picocli" @@ -12,4 +13,4 @@ metadata: languages: - "java" - "kotlin" - artifact: "io.quarkus:quarkus-project-core-extension-codestarts" + artifact: "io.quarkus:quarkus-project-core-extension-codestarts" \ No newline at end of file diff --git a/extensions/pom.xml b/extensions/pom.xml index f848f60558219..22b71363b1f42 100644 --- a/extensions/pom.xml +++ b/extensions/pom.xml @@ -197,6 +197,12 @@ + + + src/main/resources + true + + org.apache.maven.plugins diff --git a/extensions/quartz/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/quartz/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 67% rename from extensions/quartz/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/quartz/runtime/src/main/resources/META-INF/quarkus-extension.yaml index b34bb338a30c2..da544ffb6e119 100644 --- a/extensions/quartz/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/quartz/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Quartz" metadata: keywords: @@ -9,4 +10,4 @@ metadata: guide: "https://quarkus.io/guides/quartz" categories: - "miscellaneous" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 64% rename from extensions/qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 6ad09433c8c7e..6a620c024efdf 100644 --- a/extensions/qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Qute Templating" metadata: keywords: @@ -7,4 +8,4 @@ metadata: guide: "https://quarkus.io/guides/qute" categories: - "miscellaneous" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/reactive-datasource/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/reactive-datasource/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 62% rename from extensions/reactive-datasource/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/reactive-datasource/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 6b962fba7cf3a..a6bce25008265 100644 --- a/extensions/reactive-datasource/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/reactive-datasource/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Reactive datasource configuration" metadata: keywords: @@ -7,4 +8,4 @@ metadata: categories: - "data" status: "stable" - unlisted: true + unlisted: true \ No newline at end of file diff --git a/extensions/reactive-db2-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/reactive-db2-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 73% rename from extensions/reactive-db2-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/reactive-db2-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 586ab0f1da8f0..f3c2309998250 100644 --- a/extensions/reactive-db2-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/reactive-db2-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Reactive DB2 client" metadata: keywords: @@ -13,4 +14,4 @@ metadata: categories: - "data" - "reactive" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/reactive-messaging-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/reactive-messaging-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 66% rename from extensions/reactive-messaging-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/reactive-messaging-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 1dea2a0fa9f6c..e1b4386991ef7 100644 --- a/extensions/reactive-messaging-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/reactive-messaging-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Reactive HTTP and WebSocket Connector" metadata: keywords: @@ -9,4 +10,4 @@ metadata: - "web" - "reactive" - "messaging" - status: "experimental" + status: "experimental" \ No newline at end of file diff --git a/extensions/reactive-mysql-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/reactive-mysql-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 74% rename from extensions/reactive-mysql-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/reactive-mysql-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 7aa38b306fb18..cb6b95574712c 100644 --- a/extensions/reactive-mysql-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/reactive-mysql-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Reactive MySQL client" metadata: keywords: @@ -13,4 +14,4 @@ metadata: categories: - "data" - "reactive" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/reactive-pg-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/reactive-pg-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 74% rename from extensions/reactive-pg-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/reactive-pg-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 05aacbfb639f4..0f76a2f2fcc08 100644 --- a/extensions/reactive-pg-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/reactive-pg-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Reactive PostgreSQL client" metadata: keywords: @@ -13,4 +14,4 @@ metadata: categories: - "data" - "reactive" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/reactive-streams-operators/mutiny-reactive-streams-operators/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/reactive-streams-operators/mutiny-reactive-streams-operators/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 66% rename from extensions/reactive-streams-operators/mutiny-reactive-streams-operators/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/reactive-streams-operators/mutiny-reactive-streams-operators/runtime/src/main/resources/META-INF/quarkus-extension.yaml index ee5f5324e5db8..0f4a1092cef86 100644 --- a/extensions/reactive-streams-operators/mutiny-reactive-streams-operators/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/reactive-streams-operators/mutiny-reactive-streams-operators/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "SmallRye Mutiny Reactive Streams Operators" metadata: keywords: @@ -7,4 +8,4 @@ metadata: categories: - "reactive" status: "stable" - unlisted: true + unlisted: true \ No newline at end of file diff --git a/extensions/reactive-streams-operators/smallrye-reactive-streams-operators/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/reactive-streams-operators/smallrye-reactive-streams-operators/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 86% rename from extensions/reactive-streams-operators/smallrye-reactive-streams-operators/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/reactive-streams-operators/smallrye-reactive-streams-operators/runtime/src/main/resources/META-INF/quarkus-extension.yaml index f3ac4256e445b..2630e9ea12d28 100644 --- a/extensions/reactive-streams-operators/smallrye-reactive-streams-operators/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/reactive-streams-operators/smallrye-reactive-streams-operators/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} # This extension is deprecated and the upstream project is now in maintenance-only mode # It is recommended to use the quarkus-mutiny-reactive-streams-operators extension instead name: "SmallRye Reactive Streams Operators" @@ -12,4 +13,3 @@ metadata: categories: - "reactive" status: "stable" - diff --git a/extensions/reactive-streams-operators/smallrye-reactive-type-converters/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/reactive-streams-operators/smallrye-reactive-type-converters/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 75% rename from extensions/reactive-streams-operators/smallrye-reactive-type-converters/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/reactive-streams-operators/smallrye-reactive-type-converters/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 163d70f68b350..47f9989d5076a 100644 --- a/extensions/reactive-streams-operators/smallrye-reactive-type-converters/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/reactive-streams-operators/smallrye-reactive-type-converters/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "SmallRye Reactive Type Converters" metadata: keywords: @@ -10,4 +11,4 @@ metadata: categories: - "reactive" status: "stable" - unlisted: true + unlisted: true \ No newline at end of file diff --git a/extensions/redis-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/redis-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 72% rename from extensions/redis-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/redis-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 52f1aacbc2b3b..f185e994c04d1 100644 --- a/extensions/redis-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/redis-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Redis Client" metadata: keywords: @@ -12,4 +13,4 @@ metadata: categories: - "data" - "reactive" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/resteasy-classic/rest-client-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-classic/rest-client-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 70% rename from extensions/resteasy-classic/rest-client-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-classic/rest-client-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 4d66fad1169b8..eb570b4350167 100644 --- a/extensions/resteasy-classic/rest-client-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-classic/rest-client-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "REST Client Jackson" metadata: keywords: @@ -11,4 +12,4 @@ metadata: categories: - "web" - "serialization" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/resteasy-classic/rest-client-jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-classic/rest-client-jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 68% rename from extensions/resteasy-classic/rest-client-jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-classic/rest-client-jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 25c6fd88fe662..47dee6aee14ae 100644 --- a/extensions/resteasy-classic/rest-client-jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-classic/rest-client-jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "REST Client JAXB" metadata: keywords: @@ -10,4 +11,4 @@ metadata: categories: - "web" - "serialization" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/resteasy-classic/rest-client-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-classic/rest-client-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 70% rename from extensions/resteasy-classic/rest-client-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-classic/rest-client-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml index b319d5b3bbaac..92da244ecd33d 100644 --- a/extensions/resteasy-classic/rest-client-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-classic/rest-client-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "REST Client JSON-B" metadata: keywords: @@ -11,4 +12,4 @@ metadata: categories: - "web" - "serialization" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/resteasy-classic/rest-client-mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-classic/rest-client-mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 70% rename from extensions/resteasy-classic/rest-client-mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-classic/rest-client-mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml index bdfcb0dab66b4..e302fa1d14664 100644 --- a/extensions/resteasy-classic/rest-client-mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-classic/rest-client-mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Mutiny support for REST Client" metadata: keywords: @@ -10,4 +11,4 @@ metadata: categories: - "web" - "reactive" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/resteasy-classic/rest-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-classic/rest-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 68% rename from extensions/resteasy-classic/rest-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-classic/rest-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 80829cb272683..f9c87a42a1fbb 100644 --- a/extensions/resteasy-classic/rest-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-classic/rest-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "REST Client" metadata: keywords: @@ -7,4 +8,4 @@ metadata: - "microprofile-rest-client" guide: "https://quarkus.io/guides/rest-client" categories: - - "web" + - "web" \ No newline at end of file diff --git a/extensions/resteasy-classic/resteasy-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-classic/resteasy-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 63% rename from extensions/resteasy-classic/resteasy-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-classic/resteasy-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 2f06ccb93ddb9..87290867e1648 100644 --- a/extensions/resteasy-classic/resteasy-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-classic/resteasy-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "RESTEasy JAX-RS Common" metadata: keywords: @@ -9,4 +10,4 @@ metadata: categories: - "web" status: "stable" - unlisted: true + unlisted: true \ No newline at end of file diff --git a/extensions/resteasy-classic/resteasy-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-classic/resteasy-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 69% rename from extensions/resteasy-classic/resteasy-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-classic/resteasy-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 6dd65780d0a36..f3fa9ec625068 100644 --- a/extensions/resteasy-classic/resteasy-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-classic/resteasy-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "RESTEasy Jackson" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: keywords: - "resteasy-jackson" @@ -11,4 +12,4 @@ metadata: categories: - "web" - "serialization" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/resteasy-classic/resteasy-jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-classic/resteasy-jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 64% rename from extensions/resteasy-classic/resteasy-jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-classic/resteasy-jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml index f67251ccfcbae..00a1eb30641ec 100644 --- a/extensions/resteasy-classic/resteasy-jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-classic/resteasy-jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "RESTEasy JAXB" metadata: keywords: @@ -10,4 +11,4 @@ metadata: categories: - "web" - "serialization" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/resteasy-classic/resteasy-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-classic/resteasy-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 73% rename from extensions/resteasy-classic/resteasy-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-classic/resteasy-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 343c02215a97e..831b09f500ba2 100644 --- a/extensions/resteasy-classic/resteasy-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-classic/resteasy-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "RESTEasy JSON-B" metadata: keywords: @@ -13,4 +14,4 @@ metadata: categories: - "web" - "serialization" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/resteasy-classic/resteasy-multipart/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-classic/resteasy-multipart/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 71% rename from extensions/resteasy-classic/resteasy-multipart/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-classic/resteasy-multipart/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 690817653947f..597ca7b36cf9c 100644 --- a/extensions/resteasy-classic/resteasy-multipart/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-classic/resteasy-multipart/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "RESTEasy Multipart" metadata: keywords: @@ -10,4 +11,4 @@ metadata: guide: "https://quarkus.io/guides/rest-json#multipart-support" categories: - "web" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/resteasy-classic/resteasy-mutiny-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-classic/resteasy-mutiny-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml new file mode 100644 index 0000000000000..c7571f6d49707 --- /dev/null +++ b/extensions/resteasy-classic/resteasy-mutiny-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -0,0 +1,5 @@ +--- +artifact: ${project.groupId}:${project.artifactId}:${project.version} +name: "RESTEasy Mutiny Common" +metadata: + unlisted: true \ No newline at end of file diff --git a/extensions/resteasy-classic/resteasy-mutiny-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-classic/resteasy-mutiny-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template deleted file mode 100644 index 97289aa3ee076..0000000000000 --- a/extensions/resteasy-classic/resteasy-mutiny-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ /dev/null @@ -1,4 +0,0 @@ ---- -name: "RESTEasy Mutiny Common" -metadata: - unlisted: true diff --git a/extensions/resteasy-classic/resteasy-mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-classic/resteasy-mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 71% rename from extensions/resteasy-classic/resteasy-mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-classic/resteasy-mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 12a6ebce7d8aa..2b9bf99156012 100644 --- a/extensions/resteasy-classic/resteasy-mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-classic/resteasy-mutiny/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "RESTEasy Mutiny" metadata: keywords: @@ -9,4 +10,4 @@ metadata: categories: - "web" - "reactive" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/resteasy-classic/resteasy-qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-classic/resteasy-qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 82% rename from extensions/resteasy-classic/resteasy-qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-classic/resteasy-qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 6433a304f9082..287a3fb898eb5 100644 --- a/extensions/resteasy-classic/resteasy-qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-classic/resteasy-qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "RESTEasy Qute" metadata: keywords: diff --git a/extensions/resteasy-classic/resteasy-server-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-classic/resteasy-server-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 69% rename from extensions/resteasy-classic/resteasy-server-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-classic/resteasy-server-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml index f1fe1242d47b7..5c845eb91625a 100644 --- a/extensions/resteasy-classic/resteasy-server-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-classic/resteasy-server-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "RESTEasy Server Common" metadata: keywords: @@ -10,4 +11,4 @@ metadata: categories: - "web" status: "stable" - unlisted: true + unlisted: true \ No newline at end of file diff --git a/extensions/resteasy-classic/resteasy/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-classic/resteasy/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 83% rename from extensions/resteasy-classic/resteasy/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-classic/resteasy/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 5c211e4a81f05..7e5ff8085b8d8 100644 --- a/extensions/resteasy-classic/resteasy/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-classic/resteasy/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "RESTEasy JAX-RS" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: short-name: "jax-rs" keywords: @@ -16,4 +17,4 @@ metadata: - "java" - "kotlin" - "scala" - artifact: "io.quarkus:quarkus-project-core-extension-codestarts" + artifact: "io.quarkus:quarkus-project-core-extension-codestarts" \ No newline at end of file diff --git a/extensions/resteasy-reactive/jaxrs-client-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-reactive/jaxrs-client-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 62% rename from extensions/resteasy-reactive/jaxrs-client-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-reactive/jaxrs-client-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 6cab31351a976..017b6156735b3 100644 --- a/extensions/resteasy-reactive/jaxrs-client-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-reactive/jaxrs-client-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "JAX-RS Client Reactive" metadata: keywords: @@ -8,4 +9,4 @@ metadata: - "resteasy-reactive" categories: - "web" - status: "experimental" + status: "experimental" \ No newline at end of file diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml new file mode 100644 index 0000000000000..3419b80bbc9d9 --- /dev/null +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -0,0 +1,5 @@ +--- +artifact: ${project.groupId}:${project.artifactId}:${project.version} +name: "RESTEasy Reactive Common" +metadata: + unlisted: true \ No newline at end of file diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template deleted file mode 100644 index cab22db2f85ce..0000000000000 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ /dev/null @@ -1,4 +0,0 @@ ---- -name: "RESTEasy Reactive Common" -metadata: - unlisted: true \ No newline at end of file diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 50% rename from extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 9837f9bb34798..8c6790fe9535f 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "RESTEasy Reactive Jackson Common" metadata: unlisted: true \ No newline at end of file diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 86% rename from extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml index fa2cf527f96fa..0fdd0716aed20 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "RESTEasy Reactive Jackson" metadata: short-name: "resteasy-reactive-jackson" @@ -20,4 +21,4 @@ metadata: - "java" - "kotlin" - "scala" - artifact: "io.quarkus:quarkus-project-core-extension-codestarts" + artifact: "io.quarkus:quarkus-project-core-extension-codestarts" \ No newline at end of file diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 85% rename from extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 2b19e2ea94e93..0fd65e4c18e5b 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "RESTEasy Reactive JSON-B" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: short-name: "resteasy-reactive-jsonb" keywords: @@ -19,4 +20,4 @@ metadata: - "java" - "kotlin" - "scala" - artifact: "io.quarkus:quarkus-project-core-extension-codestarts" + artifact: "io.quarkus:quarkus-project-core-extension-codestarts" \ No newline at end of file diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-links/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-reactive/quarkus-resteasy-reactive-links/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 83% rename from extensions/resteasy-reactive/quarkus-resteasy-reactive-links/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-reactive/quarkus-resteasy-reactive-links/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 6f5015609223a..a22d049ed09c0 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive-links/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive-links/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "RESTEasy Reactive Links" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: short-name: "resteasy-reactive-links" keywords: @@ -15,4 +16,4 @@ metadata: - "java" - "kotlin" - "scala" - artifact: "io.quarkus:quarkus-project-core-extension-codestarts" + artifact: "io.quarkus:quarkus-project-core-extension-codestarts" \ No newline at end of file diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-reactive/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 76% rename from extensions/resteasy-reactive/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-reactive/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 22fb2756cf9cd..baeb269fec9e5 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive-problem/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: Quarkus Resteasy Reactive Problem +artifact: ${project.groupId}:${project.artifactId}:${project.version} #description: Quarkus Resteasy Reactive Problem ... metadata: # keywords: diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-reactive/quarkus-resteasy-reactive-qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 83% rename from extensions/resteasy-reactive/quarkus-resteasy-reactive-qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-reactive/quarkus-resteasy-reactive-qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml index da8a7a32ac1f4..7b14b66f4189b 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive-qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive-qute/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "RESTEasy Reactive Qute" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: keywords: - "templating" @@ -15,4 +16,3 @@ metadata: - "kotlin" - "scala" artifact: "io.quarkus:quarkus-project-core-extension-codestarts" - diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-servlet/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-reactive/quarkus-resteasy-reactive-servlet/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 84% rename from extensions/resteasy-reactive/quarkus-resteasy-reactive-servlet/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-reactive/quarkus-resteasy-reactive-servlet/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 98e00fd0e8915..1d96b78f2d584 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive-servlet/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive-servlet/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "Quarkus RESTEasy Reactive Servlet" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: unlisted: true short-name: "quarkus-resteasy-reactive-servlet" @@ -16,4 +17,4 @@ metadata: - "java" - "kotlin" - "scala" - artifact: "io.quarkus:quarkus-project-core-extension-codestarts" + artifact: "io.quarkus:quarkus-project-core-extension-codestarts" \ No newline at end of file diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 82% rename from extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 03324472adbb7..5e47ed7a1e0d5 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "RESTEasy Reactive" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: short-name: "resteasy-reactive" keywords: @@ -15,4 +16,4 @@ metadata: - "java" - "kotlin" - "scala" - artifact: "io.quarkus:quarkus-project-core-extension-codestarts" + artifact: "io.quarkus:quarkus-project-core-extension-codestarts" \ No newline at end of file diff --git a/extensions/resteasy-reactive/rest-client-reactive-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-reactive/rest-client-reactive-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 85% rename from extensions/resteasy-reactive/rest-client-reactive-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-reactive/rest-client-reactive-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml index d5e141fad045d..4e7c6a157b820 100644 --- a/extensions/resteasy-reactive/rest-client-reactive-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-reactive/rest-client-reactive-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "REST Client Reactive Jackson" metadata: keywords: @@ -19,4 +20,4 @@ metadata: - "java" - "kotlin" - "scala" - artifact: "io.quarkus:quarkus-project-core-extension-codestarts" + artifact: "io.quarkus:quarkus-project-core-extension-codestarts" \ No newline at end of file diff --git a/extensions/resteasy-reactive/rest-client-reactive/pom.xml b/extensions/resteasy-reactive/rest-client-reactive/pom.xml index 2d96afa4602a3..e85fab3cf5a7f 100644 --- a/extensions/resteasy-reactive/rest-client-reactive/pom.xml +++ b/extensions/resteasy-reactive/rest-client-reactive/pom.xml @@ -3,10 +3,10 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> - quarkus-build-parent + quarkus-extensions-parent io.quarkus 999-SNAPSHOT - ../../../build-parent/pom.xml + ../../pom.xml 4.0.0 diff --git a/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 82% rename from extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 0813536db403c..2a16939bb46cc 100644 --- a/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "REST Client Reactive" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: keywords: - "rest-client" @@ -14,4 +15,4 @@ metadata: - "java" - "kotlin" - "scala" - artifact: "io.quarkus:quarkus-project-core-extension-codestarts" + artifact: "io.quarkus:quarkus-project-core-extension-codestarts" \ No newline at end of file diff --git a/extensions/scala/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/scala/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 74% rename from extensions/scala/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/scala/runtime/src/main/resources/META-INF/quarkus-extension.yaml index b4850dd17f50c..23e3fe25bdc26 100644 --- a/extensions/scala/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/scala/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "Scala" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: keywords: - "scala" @@ -8,4 +9,4 @@ metadata: codestart: name: "scala" kind: "core" - artifact: "io.quarkus:quarkus-project-core-extension-codestarts" + artifact: "io.quarkus:quarkus-project-core-extension-codestarts" \ No newline at end of file diff --git a/extensions/scheduler/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/scheduler/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 67% rename from extensions/scheduler/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/scheduler/runtime/src/main/resources/META-INF/quarkus-extension.yaml index d8bdef06be207..72dbe49d9de1d 100644 --- a/extensions/scheduler/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/scheduler/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Scheduler - tasks" metadata: keywords: @@ -8,4 +9,4 @@ metadata: guide: "https://quarkus.io/guides/scheduler" categories: - "miscellaneous" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/security-jpa/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/security-jpa/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 66% rename from extensions/security-jpa/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/security-jpa/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 095ffee067044..e968b659d178b 100644 --- a/extensions/security-jpa/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/security-jpa/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Security JPA" metadata: keywords: @@ -9,4 +10,4 @@ metadata: guide: "https://quarkus.io/guides/security-jpa" categories: - "security" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/security/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/security/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 64% rename from extensions/security/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/security/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 7c5c8625b73ae..f5213ba32660f 100644 --- a/extensions/security/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/security/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Security" metadata: unlisted: true diff --git a/extensions/smallrye-context-propagation/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/smallrye-context-propagation/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 78% rename from extensions/smallrye-context-propagation/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/smallrye-context-propagation/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 77db88b64d34f..dd9a4065f5de2 100644 --- a/extensions/smallrye-context-propagation/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/smallrye-context-propagation/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "SmallRye Context Propagation" metadata: short-name: "context propagation" @@ -11,4 +12,4 @@ metadata: guide: "https://quarkus.io/guides/context-propagation" categories: - "reactive" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/smallrye-fault-tolerance/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/smallrye-fault-tolerance/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 75% rename from extensions/smallrye-fault-tolerance/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/smallrye-fault-tolerance/runtime/src/main/resources/META-INF/quarkus-extension.yaml index cce1a786b4e0b..78c654e35639d 100644 --- a/extensions/smallrye-fault-tolerance/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/smallrye-fault-tolerance/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "SmallRye Fault Tolerance" metadata: keywords: @@ -10,4 +11,4 @@ metadata: guide: "https://quarkus.io/guides/microprofile-fault-tolerance" categories: - "cloud" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/smallrye-graphql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/smallrye-graphql/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 72% rename from extensions/smallrye-graphql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/smallrye-graphql/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 3c0c90bc7a968..b5649d310e911 100644 --- a/extensions/smallrye-graphql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/smallrye-graphql/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "SmallRye GraphQL" metadata: short-name: "graphql" @@ -10,4 +11,4 @@ metadata: categories: - "web" guide: "https://quarkus.io/guides/microprofile-graphql" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/smallrye-health/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/smallrye-health/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 75% rename from extensions/smallrye-health/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/smallrye-health/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 944c0dee9e94f..cb2a38e533001 100644 --- a/extensions/smallrye-health/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/smallrye-health/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "SmallRye Health" metadata: short-name: "health" @@ -11,4 +12,4 @@ metadata: guide: "https://quarkus.io/guides/microprofile-health" categories: - "cloud" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/smallrye-jwt-build/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/smallrye-jwt-build/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 70% rename from extensions/smallrye-jwt-build/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/smallrye-jwt-build/runtime/src/main/resources/META-INF/quarkus-extension.yaml index d936fa36fa35c..0598f368d0d63 100644 --- a/extensions/smallrye-jwt-build/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/smallrye-jwt-build/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "SmallRye JWT Build" metadata: keywords: @@ -9,4 +10,4 @@ metadata: guide: "https://quarkus.io/guides/security-jwt" categories: - "security" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/smallrye-jwt/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/smallrye-jwt/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 69% rename from extensions/smallrye-jwt/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/smallrye-jwt/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 78721e1abaa56..51bc48bb0a798 100644 --- a/extensions/smallrye-jwt/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/smallrye-jwt/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "SmallRye JWT" metadata: keywords: @@ -10,4 +11,4 @@ metadata: categories: - "web" - "security" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/smallrye-metrics/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/smallrye-metrics/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 74% rename from extensions/smallrye-metrics/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/smallrye-metrics/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 9d61c5d9a9376..da763f3afdff1 100644 --- a/extensions/smallrye-metrics/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/smallrye-metrics/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "SmallRye Metrics" metadata: short-name: "metrics" @@ -11,4 +12,4 @@ metadata: guide: "https://quarkus.io/guides/microprofile-metrics" categories: - "observability" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/smallrye-openapi/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/smallrye-openapi/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 67% rename from extensions/smallrye-openapi/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/smallrye-openapi/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 9b4689cb5a240..6c2d367514ed1 100644 --- a/extensions/smallrye-openapi/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/smallrye-openapi/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "SmallRye OpenAPI" metadata: keywords: @@ -8,4 +9,4 @@ metadata: guide: "https://quarkus.io/guides/openapi-swaggerui" categories: - "web" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/smallrye-opentracing/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/smallrye-opentracing/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 72% rename from extensions/smallrye-opentracing/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/smallrye-opentracing/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 5baec77c2f94d..3e54e9a319578 100644 --- a/extensions/smallrye-opentracing/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/smallrye-opentracing/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "SmallRye OpenTracing" metadata: keywords: @@ -10,4 +11,4 @@ metadata: guide: "https://quarkus.io/guides/opentracing" categories: - "observability" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/smallrye-reactive-messaging-amqp/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/smallrye-reactive-messaging-amqp/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 69% rename from extensions/smallrye-reactive-messaging-amqp/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/smallrye-reactive-messaging-amqp/runtime/src/main/resources/META-INF/quarkus-extension.yaml index cd0fbf963b5dd..17e0d2833eb84 100644 --- a/extensions/smallrye-reactive-messaging-amqp/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/smallrye-reactive-messaging-amqp/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "SmallRye Reactive Messaging - AMQP Connector" metadata: short-name: "amqp" @@ -8,4 +9,4 @@ metadata: guide: "https://quarkus.io/guides/amqp" categories: - "messaging" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/smallrye-reactive-messaging-kafka/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/smallrye-reactive-messaging-kafka/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 70% rename from extensions/smallrye-reactive-messaging-kafka/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/smallrye-reactive-messaging-kafka/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 30665c5ef191d..73943e7be68df 100644 --- a/extensions/smallrye-reactive-messaging-kafka/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/smallrye-reactive-messaging-kafka/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "SmallRye Reactive Messaging - Kafka Connector" metadata: short-name: "kafka" @@ -8,4 +9,4 @@ metadata: guide: "https://quarkus.io/guides/kafka" categories: - "messaging" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/smallrye-reactive-messaging-mqtt/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/smallrye-reactive-messaging-mqtt/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 61% rename from extensions/smallrye-reactive-messaging-mqtt/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/smallrye-reactive-messaging-mqtt/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 81f30b1c20f09..b96d3d4a6f75f 100644 --- a/extensions/smallrye-reactive-messaging-mqtt/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/smallrye-reactive-messaging-mqtt/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "SmallRye Reactive Messaging - MQTT Connector" metadata: keywords: @@ -6,4 +7,4 @@ metadata: - "reactive-mqtt" categories: - "messaging" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/smallrye-reactive-messaging/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/smallrye-reactive-messaging/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 77% rename from extensions/smallrye-reactive-messaging/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/smallrye-reactive-messaging/runtime/src/main/resources/META-INF/quarkus-extension.yaml index d2e90414bf5eb..569fc8c3c6884 100644 --- a/extensions/smallrye-reactive-messaging/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/smallrye-reactive-messaging/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "SmallRye Reactive Messaging" metadata: keywords: diff --git a/extensions/spring-boot-properties/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/spring-boot-properties/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 70% rename from extensions/spring-boot-properties/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/spring-boot-properties/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 67fed92045dc9..b4e292dce5ec9 100644 --- a/extensions/spring-boot-properties/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/spring-boot-properties/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Quarkus Extension for Spring Boot properties" metadata: keywords: @@ -7,4 +8,4 @@ metadata: guide: "https://quarkus.io/guides/spring-boot-properties" categories: - "compatibility" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/spring-cache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/spring-cache/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 69% rename from extensions/spring-cache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/spring-cache/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 08914b43b5d6a..c6e9af5f7ef30 100644 --- a/extensions/spring-cache/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/spring-cache/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Quarkus Extension for Spring Cache API" metadata: keywords: @@ -8,4 +9,4 @@ metadata: guide: "https://quarkus.io/guides/spring-cache" categories: - "compatibility" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/spring-cloud-config-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/spring-cloud-config-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 74% rename from extensions/spring-cloud-config-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/spring-cloud-config-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 0bfef03405e79..082df0b2b8446 100644 --- a/extensions/spring-cloud-config-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/spring-cloud-config-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Quarkus Extension for Spring Cloud Config Client" metadata: keywords: @@ -9,4 +10,4 @@ metadata: guide: "https://quarkus.io/guides/spring-cloud-config-client" categories: - "compatibility" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/spring-data-jpa/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/spring-data-jpa/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 68% rename from extensions/spring-data-jpa/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/spring-data-jpa/runtime/src/main/resources/META-INF/quarkus-extension.yaml index e483c092556fc..9d21f7ae84d7d 100644 --- a/extensions/spring-data-jpa/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/spring-data-jpa/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Quarkus Extension for Spring Data JPA API" metadata: keywords: @@ -7,4 +8,4 @@ metadata: guide: "https://quarkus.io/guides/spring-data-jpa" categories: - "compatibility" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/spring-data-rest/pom.xml b/extensions/spring-data-rest/pom.xml index e5f65f33fd643..0901971381fed 100644 --- a/extensions/spring-data-rest/pom.xml +++ b/extensions/spring-data-rest/pom.xml @@ -3,10 +3,10 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - quarkus-build-parent + quarkus-extensions-parent io.quarkus 999-SNAPSHOT - ../../build-parent/pom.xml + ../pom.xml 4.0.0 diff --git a/extensions/spring-data-rest/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/spring-data-rest/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 72% rename from extensions/spring-data-rest/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/spring-data-rest/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 2dff6210c1680..f8cab56ce4c5a 100644 --- a/extensions/spring-data-rest/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/spring-data-rest/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Quarkus Extension for Spring Data REST" metadata: keywords: @@ -10,4 +11,4 @@ metadata: guide: "https://quarkus.io/guides/spring-data-rest" categories: - "compatibility" - status: "experimental" + status: "experimental" \ No newline at end of file diff --git a/extensions/spring-di/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/spring-di/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 66% rename from extensions/spring-di/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/spring-di/runtime/src/main/resources/META-INF/quarkus-extension.yaml index d115a8b5130ff..863a954ded7b2 100644 --- a/extensions/spring-di/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/spring-di/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Quarkus Extension for Spring DI API" metadata: keywords: @@ -7,4 +8,4 @@ metadata: guide: "https://quarkus.io/guides/spring-di" categories: - "compatibility" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/spring-scheduled/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/spring-scheduled/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 68% rename from extensions/spring-scheduled/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/spring-scheduled/runtime/src/main/resources/META-INF/quarkus-extension.yaml index d2dc0ecfd646d..6f74461bad7be 100644 --- a/extensions/spring-scheduled/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/spring-scheduled/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "Quarkus Extension for Spring Scheduled" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: keywords: - "spring-scheduled" @@ -6,4 +7,4 @@ metadata: guide: "https://quarkus.io/guides/spring-scheduled" categories: - "compatibility" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/spring-security/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/spring-security/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 70% rename from extensions/spring-security/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/spring-security/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 4796b70b7d479..58d8a1213b68e 100644 --- a/extensions/spring-security/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/spring-security/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Quarkus Extension for Spring Security API" metadata: keywords: @@ -8,4 +9,4 @@ metadata: guide: "https://quarkus.io/guides/spring-security" categories: - "compatibility" - status: "preview" + status: "preview" \ No newline at end of file diff --git a/extensions/spring-web/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/spring-web/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 83% rename from extensions/spring-web/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/spring-web/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 6a89b9b50640c..c38c9342b33f9 100644 --- a/extensions/spring-web/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/spring-web/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "Quarkus Extension for Spring Web API" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: keywords: - "spring-web" @@ -14,4 +15,3 @@ metadata: - "kotlin" - "scala" artifact: "io.quarkus:quarkus-project-core-extension-codestarts" - diff --git a/extensions/swagger-ui/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/swagger-ui/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 63% rename from extensions/swagger-ui/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/swagger-ui/runtime/src/main/resources/META-INF/quarkus-extension.yaml index f1892280c099b..e7909aae7cd08 100644 --- a/extensions/swagger-ui/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/swagger-ui/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Swagger UI" metadata: keywords: @@ -6,4 +7,4 @@ metadata: - "openapi" guide: "https://quarkus.io/guides/openapi-swaggerui" status: stable - unlisted: true + unlisted: true \ No newline at end of file diff --git a/extensions/tika/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/tika/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 62% rename from extensions/tika/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/tika/runtime/src/main/resources/META-INF/quarkus-extension.yaml index bb5e3df6a9329..88ef7341b62c9 100644 --- a/extensions/tika/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/tika/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Apache Tika" metadata: keywords: @@ -7,4 +8,4 @@ metadata: categories: - "miscellaneous" guide: "https://quarkus.io/guides/tika" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/undertow/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/undertow/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 61% rename from extensions/undertow/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/undertow/runtime/src/main/resources/META-INF/quarkus-extension.yaml index e4bb452f865ea..db9a66b9e544e 100644 --- a/extensions/undertow/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/undertow/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Undertow Servlet" metadata: short-name: "servlet" @@ -8,4 +9,4 @@ metadata: - "http" categories: - "web" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/vault/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/vault/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 69% rename from extensions/vault/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/vault/runtime/src/main/resources/META-INF/quarkus-extension.yaml index cc1327386b415..e8d313b41bc76 100644 --- a/extensions/vault/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/vault/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Vault" metadata: keywords: diff --git a/extensions/vertx-core/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/vertx-core/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 66% rename from extensions/vertx-core/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/vertx-core/runtime/src/main/resources/META-INF/quarkus-extension.yaml index c076fed1365d9..840e81675de46 100644 --- a/extensions/vertx-core/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/vertx-core/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Eclipse Vert.x - Core" metadata: keywords: @@ -9,4 +10,4 @@ metadata: categories: - "reactive" status: "stable" - unlisted: true + unlisted: true \ No newline at end of file diff --git a/extensions/vertx-graphql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/vertx-graphql/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 63% rename from extensions/vertx-graphql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/vertx-graphql/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 369891a5e4de7..395881cb12348 100644 --- a/extensions/vertx-graphql/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/vertx-graphql/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Eclipse Vert.x GraphQL" metadata: keywords: @@ -9,4 +10,4 @@ metadata: - "vertx-graphql" categories: - "web" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/vertx-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/vertx-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 70% rename from extensions/vertx-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/vertx-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml index b0c67e88b053a..ebb7ba2573f41 100644 --- a/extensions/vertx-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/vertx-http/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Eclipse Vert.x - HTTP" metadata: keywords: @@ -12,4 +13,4 @@ metadata: - "web" - "reactive" status: "stable" - unlisted: true + unlisted: true \ No newline at end of file diff --git a/extensions/vertx-web/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/vertx-web/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 64% rename from extensions/vertx-web/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/vertx-web/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 24af706a6301b..5ff30ca8f2219 100644 --- a/extensions/vertx-web/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/vertx-web/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Reactive Routes" metadata: keywords: @@ -14,4 +15,4 @@ metadata: - "web" - "reactive" status: "stable" - guide: https://quarkus.io/guides/reactive-routes + guide: https://quarkus.io/guides/reactive-routes \ No newline at end of file diff --git a/extensions/vertx/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/vertx/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 67% rename from extensions/vertx/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/vertx/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 1ef6f8b16b77e..fa46515b2b5c1 100644 --- a/extensions/vertx/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/vertx/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Eclipse Vert.x" metadata: keywords: @@ -9,4 +10,4 @@ metadata: guide: "https://quarkus.io/guides/vertx" categories: - "reactive" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/webjars-locator/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/webjars-locator/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 61% rename from extensions/webjars-locator/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/webjars-locator/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 978daf02b110e..dedd33967ee83 100644 --- a/extensions/webjars-locator/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/webjars-locator/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "WebJar Locator" metadata: short-name: "webjars-locator" @@ -8,4 +9,4 @@ metadata: guide: "" categories: - "web" - status: "stable" + status: "stable" \ No newline at end of file diff --git a/extensions/websockets/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/extensions/websockets/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 84% rename from extensions/websockets/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to extensions/websockets/runtime/src/main/resources/META-INF/quarkus-extension.yaml index db48e5f6ecf9f..b7274cd07740b 100644 --- a/extensions/websockets/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/extensions/websockets/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ name: "WebSockets" +artifact: ${project.groupId}:${project.artifactId}:${project.version} metadata: short-name: "websockets" keywords: @@ -15,4 +16,4 @@ metadata: name: "undertow-websockets" kind: "example" languages: "java" - artifact: "io.quarkus:quarkus-project-core-extension-codestarts" + artifact: "io.quarkus:quarkus-project-core-extension-codestarts" \ No newline at end of file diff --git a/independent-projects/bootstrap/maven-plugin/src/main/java/io/quarkus/maven/ExtensionDescriptorMojo.java b/independent-projects/bootstrap/maven-plugin/src/main/java/io/quarkus/maven/ExtensionDescriptorMojo.java index 3f9e96ca7eb4b..f04e504b4d504 100644 --- a/independent-projects/bootstrap/maven-plugin/src/main/java/io/quarkus/maven/ExtensionDescriptorMojo.java +++ b/independent-projects/bootstrap/maven-plugin/src/main/java/io/quarkus/maven/ExtensionDescriptorMojo.java @@ -85,7 +85,6 @@ public class ExtensionDescriptorMojo extends AbstractMojo { private static final String GROUP_ID = "group-id"; private static final String ARTIFACT_ID = "artifact-id"; private static final String METADATA = "metadata"; - public static final String TEMPLATE = ".template"; /** * The entry point to Aether, i.e. the component doing all the work. @@ -302,30 +301,19 @@ public void execute() throws MojoExecutionException { } // extension.json - File extensionFileTemplate = null; - if (extensionFile == null) { extensionFile = new File(outputDirectory, "META-INF" + File.separator + BootstrapConstants.QUARKUS_EXTENSION_FILE_NAME); - extensionFileTemplate = new File(outputDirectory, - "META-INF" + File.separator + BootstrapConstants.QUARKUS_EXTENSION_FILE_NAME + TEMPLATE); - } else { - extensionFileTemplate = new File(extensionFile.getParent(), extensionFile.getName() + TEMPLATE); } ObjectNode extObject; - if (!extensionFile.exists() && !extensionFileTemplate.exists()) { + if (!extensionFile.exists()) { // if does not exist look for fallback .json - // template is not supported for json extensionFile = new File(extensionFile.getParent(), "quarkus-extension.json"); - extensionFileTemplate = null; } ObjectMapper mapper = null; - if (extensionFileTemplate != null && extensionFileTemplate.exists()) { - mapper = getMapper(true); - extObject = readJsonNode(extensionFileTemplate.toPath(), mapper); - } else if (extensionFile.exists()) { + if (extensionFile.exists()) { mapper = getMapper(extensionFile.toString().endsWith(".yaml")); extObject = readJsonNode(extensionFile.toPath(), mapper); } else { diff --git a/integration-tests/gradle/src/test/resources/test-resources-in-build-steps/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/integration-tests/gradle/src/test/resources/test-resources-in-build-steps/runtime/src/main/resources/META-INF/quarkus-extension.yaml new file mode 100644 index 0000000000000..b5c50fa3eb2aa --- /dev/null +++ b/integration-tests/gradle/src/test/resources/test-resources-in-build-steps/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -0,0 +1,4 @@ +--- +artifact: org.acme:acme-ext:1.0-SNAPSHOT +metadata: {} +name: "Acme Ext - Runtime" \ No newline at end of file diff --git a/integration-tests/gradle/src/test/resources/test-resources-in-build-steps/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/integration-tests/gradle/src/test/resources/test-resources-in-build-steps/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template deleted file mode 100644 index 3873c2463563c..0000000000000 --- a/integration-tests/gradle/src/test/resources/test-resources-in-build-steps/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ /dev/null @@ -1,6 +0,0 @@ ---- -metadata: {} -group-id: "org.acme" -artifact-id: "acme-ext" -version: "1.0-SNAPSHOT" -name: "Acme Ext - Runtime" diff --git a/test-framework/jacoco/runtime/pom.xml b/test-framework/jacoco/runtime/pom.xml index 0f114c3cdb438..2e4e99184be8b 100644 --- a/test-framework/jacoco/runtime/pom.xml +++ b/test-framework/jacoco/runtime/pom.xml @@ -51,6 +51,12 @@ + + + src/main/resources + true + + io.quarkus diff --git a/test-framework/jacoco/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template b/test-framework/jacoco/runtime/src/main/resources/META-INF/quarkus-extension.yaml similarity index 65% rename from test-framework/jacoco/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template rename to test-framework/jacoco/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 7e233728e2cf8..1e3597087719f 100644 --- a/test-framework/jacoco/runtime/src/main/resources/META-INF/quarkus-extension.yaml.template +++ b/test-framework/jacoco/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,5 @@ --- +artifact: ${project.groupId}:${project.artifactId}:${project.version} name: "Jacoco - Code Coverage" metadata: keywords: @@ -7,4 +8,4 @@ metadata: guide: "https://quarkus.io/guides/tests-with-coverage" categories: - "miscellaneous" - status: "experimental" + status: "experimental" \ No newline at end of file From 0640082c6bf13aa60cbc48d902f1bcbed1b14b22 Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Mon, 17 May 2021 15:22:25 +0200 Subject: [PATCH 0101/2077] Mailer templates - make it possible to pass template attributes - e.g. to specify locale for type-safe message bundles - resolves #17185 - also require type-safe expressions in virtual method params for checked templates --- docs/src/main/asciidoc/mailer.adoc | 2 +- .../io/quarkus/mailer/i18n/AppMessages.java | 12 ++++ .../mailer/i18n/MailMessageBundleTest.java | 67 +++++++++++++++++++ .../java/io/quarkus/mailer/MailTemplate.java | 16 +++++ .../runtime/MailTemplateInstanceImpl.java | 6 ++ .../deployment/MessageBundleProcessor.java | 35 +++++++++- .../qute/deployment/QuteProcessor.java | 56 ++++++---------- .../CheckedTemplateRequireTypeSafeTest.java | 35 +++++++++- 8 files changed, 188 insertions(+), 41 deletions(-) create mode 100644 extensions/mailer/deployment/src/test/java/io/quarkus/mailer/i18n/AppMessages.java create mode 100644 extensions/mailer/deployment/src/test/java/io/quarkus/mailer/i18n/MailMessageBundleTest.java diff --git a/docs/src/main/asciidoc/mailer.adoc b/docs/src/main/asciidoc/mailer.adoc index 563cf41bb3ab6..dc2493813a8aa 100644 --- a/docs/src/main/asciidoc/mailer.adoc +++ b/docs/src/main/asciidoc/mailer.adoc @@ -312,7 +312,7 @@ public Uni send() { <1> <1> The method returns a `Uni` <2> Transform the `Uni` returned by `MailTemplate` into `Unit` -[[testing]]] +[[testing]] == Testing email sending Because it is very inconvenient to send emails during development and testing, you can set the `quarkus.mailer.mock` boolean diff --git a/extensions/mailer/deployment/src/test/java/io/quarkus/mailer/i18n/AppMessages.java b/extensions/mailer/deployment/src/test/java/io/quarkus/mailer/i18n/AppMessages.java new file mode 100644 index 0000000000000..a08d1de71f7be --- /dev/null +++ b/extensions/mailer/deployment/src/test/java/io/quarkus/mailer/i18n/AppMessages.java @@ -0,0 +1,12 @@ +package io.quarkus.mailer.i18n; + +import io.quarkus.qute.i18n.Message; +import io.quarkus.qute.i18n.MessageBundle; + +@MessageBundle +public interface AppMessages { + + @Message("Hello {name}!") + String hello_name(String name); + +} diff --git a/extensions/mailer/deployment/src/test/java/io/quarkus/mailer/i18n/MailMessageBundleTest.java b/extensions/mailer/deployment/src/test/java/io/quarkus/mailer/i18n/MailMessageBundleTest.java new file mode 100644 index 0000000000000..c0fcae9c12963 --- /dev/null +++ b/extensions/mailer/deployment/src/test/java/io/quarkus/mailer/i18n/MailMessageBundleTest.java @@ -0,0 +1,67 @@ +package io.quarkus.mailer.i18n; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; +import java.util.Locale; + +import javax.inject.Inject; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.mailer.Mail; +import io.quarkus.mailer.MailTemplate.MailTemplateInstance; +import io.quarkus.mailer.MockMailbox; +import io.quarkus.qute.CheckedTemplate; +import io.quarkus.test.QuarkusUnitTest; + +public class MailMessageBundleTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addClasses(Templates.class, AppMessages.class) + .addAsResource("mock-config.properties", "application.properties") + .addAsResource(new StringAsset( + "hello_name=Hallo {name}!"), + "messages/msg_de.properties") + .addAsResource(new StringAsset("" + + "{msg:hello_name(name)}"), "templates/MailMessageBundleTest/hello.txt")); + + @Inject + MockMailbox mailbox; + + @Test + public void testSend() { + mailbox.clear(); + + Templates.hello("Lu").to("quarkus@quarkus.io").subject("Test").send().await().indefinitely(); + + List sent = mailbox.getMessagesSentTo("quarkus@quarkus.io"); + assertEquals(1, sent.size()); + Mail english = sent.get(0); + assertEquals("Test", english.getSubject()); + assertEquals("Hello Lu!", english.getText()); + + // Set the locale attribute + Templates.hello("Lu").to("quarkus@quarkus.io").subject("Test").setAttribute("locale", Locale.GERMAN).send().await() + .indefinitely(); + + assertEquals(2, sent.size()); + Mail german = sent.get(1); + assertEquals("Test", german.getSubject()); + assertEquals("Hallo Lu!", german.getText()); + } + + @CheckedTemplate + static class Templates { + + static native MailTemplateInstance hello(String name); + + } + +} diff --git a/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/MailTemplate.java b/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/MailTemplate.java index cac9314220909..8df9f5142cd86 100644 --- a/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/MailTemplate.java +++ b/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/MailTemplate.java @@ -52,8 +52,24 @@ interface MailTemplateInstance { MailTemplateInstance addInlineAttachment(String name, File file, String contentType, String contentId); + /** + * + * @param key + * @param value + * @return self + * @see io.quarkus.qute.TemplateInstance#data(String, Object) + */ MailTemplateInstance data(String key, Object value); + /** + * + * @param key + * @param value + * @return self + * @see io.quarkus.qute.TemplateInstance#setAttribute(String, Object) + */ + MailTemplateInstance setAttribute(String key, Object value); + Uni send(); } diff --git a/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/MailTemplateInstanceImpl.java b/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/MailTemplateInstanceImpl.java index 469a53a9c3ddc..30bbaf17ba0d4 100644 --- a/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/MailTemplateInstanceImpl.java +++ b/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/MailTemplateInstanceImpl.java @@ -91,6 +91,12 @@ public MailTemplateInstance data(String key, Object value) { return this; } + @Override + public MailTemplateInstance setAttribute(String key, Object value) { + this.templateInstance.setAttribute(key, value); + return this; + } + @Override public Uni send() { Object variantsAttr = templateInstance.getAttribute(TemplateInstance.VARIANTS); diff --git a/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/MessageBundleProcessor.java b/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/MessageBundleProcessor.java index 3e195a3d89010..56753092ac93a 100644 --- a/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/MessageBundleProcessor.java +++ b/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/MessageBundleProcessor.java @@ -82,6 +82,7 @@ import io.quarkus.qute.i18n.MessageBundle; import io.quarkus.qute.i18n.MessageBundles; import io.quarkus.qute.runtime.MessageBundleRecorder; +import io.quarkus.qute.runtime.QuteConfig; import io.quarkus.runtime.util.StringUtil; public class MessageBundleProcessor { @@ -317,7 +318,9 @@ void validateMessageBundleMethodsInTemplates(TemplatesAnalysisBuildItem analysis List messageBundleMethods, List expressionMatches, BuildProducer incorrectExpressions, - BuildProducer implicitClasses) { + BuildProducer implicitClasses, + List checkedTemplates, + QuteConfig config) { IndexView index = beanArchiveIndex.getIndex(); Function templateIdToPathFun = new Function() { @@ -357,9 +360,26 @@ public String apply(String id) { for (Entry> exprEntry : expressions.entrySet()) { + TemplateAnalysis templateAnalysis = exprEntry.getKey(); + + String path = templateAnalysis.path; + for (String suffix : config.suffixes) { + if (path.endsWith(suffix)) { + path = path.substring(0, path.length() - (suffix.length() + 1)); + break; + } + } + CheckedTemplateBuildItem checkedTemplate = null; + for (CheckedTemplateBuildItem item : checkedTemplates) { + if (item.templateId.equals(path)) { + checkedTemplate = item; + break; + } + } + Map generatedIdsToMatches = Collections.emptyMap(); for (TemplateExpressionMatchesBuildItem templateExpressionMatchesBuildItem : expressionMatches) { - if (templateExpressionMatchesBuildItem.templateGeneratedId.equals(exprEntry.getKey().generatedId)) { + if (templateExpressionMatchesBuildItem.templateGeneratedId.equals(templateAnalysis.generatedId)) { generatedIdsToMatches = templateExpressionMatchesBuildItem.getGeneratedIdsToMatches(); break; } @@ -412,7 +432,7 @@ public String apply(String id) { QuteProcessor.validateNestedExpressions(exprEntry.getKey(), defaultBundleInterface, results, templateExtensionMethods, excludes, incorrectExpressions, expression, index, implicitClassToMembersUsed, - templateIdToPathFun, generatedIdsToMatches); + templateIdToPathFun, generatedIdsToMatches, checkedTemplate); Match match = results.get(param.toOriginalString()); if (match != null && !match.isEmpty() && !Types.isAssignableFrom(match.type(), methodParams.get(idx), index)) { @@ -423,6 +443,15 @@ public String apply(String id) { + "] does not match the type: " + match.type(), expression.getOrigin())); } + } else if (checkedTemplate != null && checkedTemplate.requireTypeSafeExpressions) { + incorrectExpressions.produce(new IncorrectExpressionBuildItem(expression.toOriginalString(), + "Only type-safe expressions are allowed in the checked template defined via: " + + checkedTemplate.method.declaringClass().name() + "." + + checkedTemplate.method.name() + + "(); an expression must be based on a checked template parameter " + + checkedTemplate.bindings.keySet() + + ", or bound via a param declaration, or the requirement must be relaxed via @CheckedTemplate(requireTypeSafeExpressions = false)", + expression.getOrigin())); } idx++; } diff --git a/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/QuteProcessor.java b/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/QuteProcessor.java index c7f7d9f68f4a2..df3a41d29277e 100644 --- a/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/QuteProcessor.java +++ b/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/QuteProcessor.java @@ -534,29 +534,15 @@ public String apply(String id) { if (expression.getNamespace().equals(EngineProducer.INJECT_NAMESPACE)) { validateInjectExpression(templateAnalysis, expression, index, incorrectExpressions, templateExtensionMethods, excludes, namedBeans, generatedIdsToMatches, - implicitClassToMembersUsed, - templateIdToPathFun); + implicitClassToMembersUsed, templateIdToPathFun, checkedTemplate); } else { continue; } } else { - if (checkedTemplate != null && checkedTemplate.requireTypeSafeExpressions && !expression.hasTypeInfo()) { - incorrectExpressions.produce(new IncorrectExpressionBuildItem(expression.toOriginalString(), - "Only type-safe expressions are allowed in the checked template defined via: " - + checkedTemplate.method.declaringClass().name() + "." - + checkedTemplate.method.name() - + "(); an expression must be based on a checked template parameter " - + checkedTemplate.bindings.keySet() - + ", or bound via a param declaration, or the requirement must be relaxed via @CheckedTemplate(requireTypeSafeExpressions = false)", - expression.getOrigin())); - continue; - } - generatedIdsToMatches.put(expression.getGeneratedId(), validateNestedExpressions(templateAnalysis, null, new HashMap<>(), templateExtensionMethods, - excludes, - incorrectExpressions, expression, index, implicitClassToMembersUsed, templateIdToPathFun, - generatedIdsToMatches)); + excludes, incorrectExpressions, expression, index, implicitClassToMembersUsed, + templateIdToPathFun, generatedIdsToMatches, checkedTemplate)); } } @@ -587,25 +573,12 @@ static String buildIgnorePattern(Iterable names) { return ignorePattern.toString(); } - /** - * @param templateAnalysis - * @param rootClazz - * @param results Map of cached results within a single expression - * @param templateExtensionMethods - * @param excludes - * @param incorrectExpressions - * @param expression - * @param index - * @param implicitClassToMembersUsed - * @param templateIdToPathFun - * @return the last match object - */ static Match validateNestedExpressions(TemplateAnalysis templateAnalysis, ClassInfo rootClazz, Map results, List templateExtensionMethods, List excludes, BuildProducer incorrectExpressions, Expression expression, IndexView index, Map> implicitClassToMembersUsed, Function templateIdToPathFun, - Map generatedIdsToMatches) { + Map generatedIdsToMatches, CheckedTemplateBuildItem checkedTemplate) { // First validate nested virtual methods for (Expression.Part part : expression.getParts()) { @@ -614,13 +587,27 @@ static Match validateNestedExpressions(TemplateAnalysis templateAnalysis, ClassI if (!results.containsKey(param.toOriginalString())) { validateNestedExpressions(templateAnalysis, null, results, templateExtensionMethods, excludes, incorrectExpressions, param, index, implicitClassToMembersUsed, templateIdToPathFun, - generatedIdsToMatches); + generatedIdsToMatches, checkedTemplate); } } } } // Then validate the expression itself Match match = new Match(index); + + if (checkedTemplate != null && checkedTemplate.requireTypeSafeExpressions && !expression.hasTypeInfo()) { + incorrectExpressions.produce(new IncorrectExpressionBuildItem(expression.toOriginalString(), + "Only type-safe expressions are allowed in the checked template defined via: " + + checkedTemplate.method.declaringClass().name() + "." + + checkedTemplate.method.name() + + "(); an expression must be based on a checked template parameter " + + checkedTemplate.bindings.keySet() + + ", or bound via a param declaration, or the requirement must be relaxed via @CheckedTemplate(requireTypeSafeExpressions = false)", + expression.getOrigin())); + results.put(expression.toOriginalString(), match); + return match; + } + if (rootClazz == null && !expression.hasTypeInfo()) { // No type info available or a namespace expression results.put(expression.toOriginalString(), match); @@ -875,7 +862,8 @@ private void validateInjectExpression(TemplateAnalysis templateAnalysis, Express BuildProducer incorrectExpressions, List templateExtensionMethods, List excludes, Map namedBeans, Map generatedIdsToMatches, - Map> implicitClassToMembersUsed, Function templateIdToPathFun) { + Map> implicitClassToMembersUsed, Function templateIdToPathFun, + CheckedTemplateBuildItem checkedTemplate) { Expression.Part firstPart = expression.getParts().get(0); if (firstPart.isVirtualMethod()) { incorrectExpressions.produce(new IncorrectExpressionBuildItem(expression.toOriginalString(), @@ -902,7 +890,7 @@ private void validateInjectExpression(TemplateAnalysis templateAnalysis, Express generatedIdsToMatches.put(expression.getGeneratedId(), validateNestedExpressions(templateAnalysis, bean.getImplClazz(), new HashMap<>(), templateExtensionMethods, excludes, incorrectExpressions, expression, index, - implicitClassToMembersUsed, templateIdToPathFun, generatedIdsToMatches)); + implicitClassToMembersUsed, templateIdToPathFun, generatedIdsToMatches, checkedTemplate)); } else { // User is injecting a non-existing bean diff --git a/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/typesafe/CheckedTemplateRequireTypeSafeTest.java b/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/typesafe/CheckedTemplateRequireTypeSafeTest.java index 18598de27ffdc..dc8ba97a3f49e 100644 --- a/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/typesafe/CheckedTemplateRequireTypeSafeTest.java +++ b/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/typesafe/CheckedTemplateRequireTypeSafeTest.java @@ -1,7 +1,12 @@ package io.quarkus.qute.deployment.typesafe; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import javax.inject.Named; +import javax.inject.Singleton; + import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.asset.StringAsset; import org.jboss.shrinkwrap.api.spec.JavaArchive; @@ -18,10 +23,24 @@ public class CheckedTemplateRequireTypeSafeTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) - .addClasses(Templates.class) - .addAsResource(new StringAsset("Hello {name}! {any}"), + .addClasses(Templates.class, Fool.class) + .addAsResource(new StringAsset("Hello {name}! {any} {inject:fool.getJoke(identifier)}"), "templates/CheckedTemplateRequireTypeSafeTest/hola.txt")) - .setExpectedException(TemplateException.class); + .assertException(t -> { + Throwable e = t; + TemplateException te = null; + while (e != null) { + if (e instanceof TemplateException) { + te = (TemplateException) e; + break; + } + e = e.getCause(); + } + assertNotNull(te); + assertTrue(te.getMessage().contains("Found template problems (2)"), te.getMessage()); + assertTrue(te.getMessage().contains("any"), te.getMessage()); + assertTrue(te.getMessage().contains("identifier"), te.getMessage()); + }); @Test public void testValidation() { @@ -35,4 +54,14 @@ static class Templates { } + @Singleton + @Named + public static class Fool { + + public String getJoke(Integer id) { + return "ok"; + } + + } + } From 3cb70e27ed7261a3391cbde6477eb486f0a967a8 Mon Sep 17 00:00:00 2001 From: Kevin Wooten Date: Mon, 10 May 2021 07:46:09 -0700 Subject: [PATCH 0102/2077] Add DevServices support for Vault extension --- bom/application/pom.xml | 5 + docs/src/main/asciidoc/vault.adoc | 46 ++++ extensions/vault/deployment-spi/pom.xml | 22 ++ .../DevServicesVaultResultBuildItem.java | 17 ++ extensions/vault/deployment/pom.xml | 14 ++ .../deployment/DevServicesVaultProcessor.java | 203 ++++++++++++++++++ extensions/vault/pom.xml | 1 + .../quarkus/vault/runtime/VaultVersions.java | 7 + .../runtime/config/DevServicesConfig.java | 76 +++++++ .../runtime/config/VaultBuildTimeConfig.java | 7 + test-framework/junit5/pom.xml | 4 + .../test/junit/NativeDevServicesHandler.java | 9 + .../vault/test/VaultTestExtension.java | 3 +- 13 files changed, 413 insertions(+), 1 deletion(-) create mode 100644 extensions/vault/deployment-spi/pom.xml create mode 100644 extensions/vault/deployment-spi/src/main/java/io/quarkus/vault/deployment/devservices/DevServicesVaultResultBuildItem.java create mode 100644 extensions/vault/deployment/src/main/java/io/quarkus/vault/deployment/DevServicesVaultProcessor.java create mode 100644 extensions/vault/runtime/src/main/java/io/quarkus/vault/runtime/VaultVersions.java create mode 100644 extensions/vault/runtime/src/main/java/io/quarkus/vault/runtime/config/DevServicesConfig.java diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 4133cbd084c0e..1170e78296f2c 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -2335,6 +2335,11 @@ quarkus-vault-deployment ${project.version} + + io.quarkus + quarkus-vault-deployment-spi + ${project.version} + io.quarkus quarkus-credentials diff --git a/docs/src/main/asciidoc/vault.adoc b/docs/src/main/asciidoc/vault.adoc index b1fe58afd35d1..44cedda2eaa6d 100644 --- a/docs/src/main/asciidoc/vault.adoc +++ b/docs/src/main/asciidoc/vault.adoc @@ -45,6 +45,11 @@ To complete this guide, you need: == Starting Vault +[TIP] +==== +Using <>, Quarkus will take care of starting Vault in dev and test mode. +==== + Let's start Vault in development mode: [source,bash, subs=attributes+] @@ -278,6 +283,11 @@ quarkus.vault.authentication.userpass.password=sinclair quarkus.vault.secret-config-kv-path=myapps/vault-quickstart/config ---- +[TIP] +==== +Using <>, Quarkus will take care of configuring the Vault connection in dev and test mode. +==== + This should mount whatever keys are stored in `secret/myapps/vault-quickstart` as Config properties. Let's verify that by adding a new endpoint in GreetingResource: @@ -508,6 +518,42 @@ path "auth/kubernetes/role/*" { You should adjust to the minimal set of access rights depending on your specific use case. +[[dev-services]] +== DevServices (Configuration Free Vault) + +Quarkus supports a feature called DevServices that allows you to create various containers without any config. +What that means in practice is that if you have Docker running and have not configured `quarkus.vault.url`, +Quarkus will automatically start a Vault container when running tests or in dev mode, and automatically +configure the connection. + +When running the production version of the application, the Vault connection needs to be configured as normal, +so if you want to include a production Vault config in your `application.properties` and continue to use DevServices +we recommend that you use the `%prod.` profile to define your Vault connection settings. + +=== Automatic Secret Engine Provisioning + +To help with provisioning the automatically managed Vault instance, you can enable certain secret engines. + +[NOTE] +==== +As mentioned above Vault containers started in dev mode automatically mount the _kv secret engine v2_ +at `secret/`. +==== + +Enable the **Transit Secret Engine** at `transit/` using: + +[source,properties] +---- +quarkus.vault.devservices.transit-enabled=true +---- + +Enable the **PKI Secret Engine** at `pki/` using: + +[source,properties] +---- +quarkus.vault.devservices.pki-enabled=true +---- + == Conclusion As a general matter, you should consider reading the extensive https://www.vaultproject.io/docs/[Vault documentation] diff --git a/extensions/vault/deployment-spi/pom.xml b/extensions/vault/deployment-spi/pom.xml new file mode 100644 index 0000000000000..17cb17e5c7435 --- /dev/null +++ b/extensions/vault/deployment-spi/pom.xml @@ -0,0 +1,22 @@ + + + + quarkus-vault-parent + io.quarkus + 999-SNAPSHOT + + 4.0.0 + + quarkus-vault-deployment-spi + Quarkus - Vault - Deployment - SPI + + + + io.quarkus + quarkus-core-deployment + + + + diff --git a/extensions/vault/deployment-spi/src/main/java/io/quarkus/vault/deployment/devservices/DevServicesVaultResultBuildItem.java b/extensions/vault/deployment-spi/src/main/java/io/quarkus/vault/deployment/devservices/DevServicesVaultResultBuildItem.java new file mode 100644 index 0000000000000..4a627a122439f --- /dev/null +++ b/extensions/vault/deployment-spi/src/main/java/io/quarkus/vault/deployment/devservices/DevServicesVaultResultBuildItem.java @@ -0,0 +1,17 @@ +package io.quarkus.vault.deployment.devservices; + +import java.util.Map; + +import io.quarkus.builder.item.SimpleBuildItem; + +public final class DevServicesVaultResultBuildItem extends SimpleBuildItem { + private final Map properties; + + public DevServicesVaultResultBuildItem(Map properties) { + this.properties = properties; + } + + public Map getProperties() { + return properties; + } +} diff --git a/extensions/vault/deployment/pom.xml b/extensions/vault/deployment/pom.xml index d351575d6122a..20068b8377136 100644 --- a/extensions/vault/deployment/pom.xml +++ b/extensions/vault/deployment/pom.xml @@ -17,6 +17,10 @@ io.quarkus quarkus-vault + + io.quarkus + quarkus-vault-deployment-spi + io.quarkus quarkus-core-deployment @@ -45,6 +49,16 @@ io.quarkus quarkus-smallrye-health-spi + + org.testcontainers + vault + + + org.hamcrest + hamcrest-core + + + io.quarkus quarkus-junit5 diff --git a/extensions/vault/deployment/src/main/java/io/quarkus/vault/deployment/DevServicesVaultProcessor.java b/extensions/vault/deployment/src/main/java/io/quarkus/vault/deployment/DevServicesVaultProcessor.java new file mode 100644 index 0000000000000..8150726014fda --- /dev/null +++ b/extensions/vault/deployment/src/main/java/io/quarkus/vault/deployment/DevServicesVaultProcessor.java @@ -0,0 +1,203 @@ +package io.quarkus.vault.deployment; + +import java.io.Closeable; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.OptionalInt; + +import org.apache.commons.lang3.RandomStringUtils; +import org.jboss.logging.Logger; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.vault.VaultContainer; + +import io.quarkus.bootstrap.classloading.QuarkusClassLoader; +import io.quarkus.deployment.IsDockerWorking; +import io.quarkus.deployment.IsNormal; +import io.quarkus.deployment.annotations.BuildProducer; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.builditem.LaunchModeBuildItem; +import io.quarkus.deployment.builditem.RunTimeConfigurationDefaultBuildItem; +import io.quarkus.deployment.builditem.ServiceStartBuildItem; +import io.quarkus.runtime.LaunchMode; +import io.quarkus.runtime.configuration.ConfigUtils; +import io.quarkus.vault.deployment.devservices.DevServicesVaultResultBuildItem; +import io.quarkus.vault.runtime.VaultVersions; +import io.quarkus.vault.runtime.config.DevServicesConfig; +import io.quarkus.vault.runtime.config.VaultBuildTimeConfig; + +public class DevServicesVaultProcessor { + private static final Logger log = Logger.getLogger(DevServicesVaultProcessor.class); + private static final String VAULT_IMAGE = "vault:" + VaultVersions.VAULT_TEST_VERSION; + private static final int VAULT_EXPOSED_PORT = 8200; + private static final String CONFIG_PREFIX = "quarkus.vault."; + private static final String URL_CONFIG_KEY = CONFIG_PREFIX + "url"; + private static final String AUTH_CONFIG_PREFIX = CONFIG_PREFIX + "authentication."; + private static final String CLIENT_TOKEN_CONFIG_KEY = AUTH_CONFIG_PREFIX + "client-token"; + private static volatile List closeables; + private static volatile DevServicesConfig capturedDevServicesConfiguration; + private static volatile boolean first = true; + private final IsDockerWorking isDockerWorking = new IsDockerWorking(true); + + @BuildStep(onlyIfNot = IsNormal.class) + public DevServicesVaultResultBuildItem startVaultContainers(LaunchModeBuildItem launchMode, + BuildProducer runTimeConfiguration, + BuildProducer serviceStartBuildItemBuildProducer, VaultBuildTimeConfig config) { + + DevServicesConfig currentDevServicesConfiguration = config.devservices; + + // figure out if we need to shut down and restart any existing Vault container + // if not and the Vault container have already started we just return + if (closeables != null) { + boolean restartRequired = launchMode.getLaunchMode() == LaunchMode.TEST; + if (!restartRequired) { + restartRequired = !currentDevServicesConfiguration.equals(capturedDevServicesConfiguration); + } + if (!restartRequired) { + return null; + } + for (Closeable closeable : closeables) { + try { + closeable.close(); + } catch (Throwable e) { + log.error("Failed to stop Vault container", e); + } + } + closeables = null; + capturedDevServicesConfiguration = null; + } + + capturedDevServicesConfiguration = currentDevServicesConfiguration; + + StartResult startResult = startContainer(currentDevServicesConfiguration); + if (startResult == null) { + return null; + } + + runTimeConfiguration.produce(new RunTimeConfigurationDefaultBuildItem(URL_CONFIG_KEY, startResult.url)); + runTimeConfiguration + .produce(new RunTimeConfigurationDefaultBuildItem(CLIENT_TOKEN_CONFIG_KEY, startResult.clientToken)); + + Map connectionProperties = new HashMap<>(); + connectionProperties.put(URL_CONFIG_KEY, startResult.url); + connectionProperties.put(CLIENT_TOKEN_CONFIG_KEY, startResult.clientToken); + + closeables = Collections.singletonList(startResult.closeable); + + if (first) { + first = false; + Runnable closeTask = new Runnable() { + @Override + public void run() { + if (closeables != null) { + for (Closeable closeable : closeables) { + try { + closeable.close(); + } catch (Throwable t) { + log.error("Failed to stop Vault container", t); + } + } + } + first = true; + closeables = null; + capturedDevServicesConfiguration = null; + } + }; + QuarkusClassLoader cl = (QuarkusClassLoader) Thread.currentThread().getContextClassLoader(); + ((QuarkusClassLoader) cl.parent()).addCloseTask(closeTask); + Thread closeHookThread = new Thread(closeTask, "Vault container shutdown thread"); + Runtime.getRuntime().addShutdownHook(closeHookThread); + ((QuarkusClassLoader) cl.parent()).addCloseTask(new Runnable() { + @Override + public void run() { + Runtime.getRuntime().removeShutdownHook(closeHookThread); + } + }); + } + return new DevServicesVaultResultBuildItem(connectionProperties); + } + + private StartResult startContainer(DevServicesConfig devServicesConfig) { + if (!devServicesConfig.enabled) { + // explicitly disabled + log.debug("Not starting devservices for Vault as it has been disabled in the config"); + return null; + } + + if (!isDockerWorking.getAsBoolean()) { + log.warn("Please configure Vault URL or get a working docker instance"); + return null; + } + + boolean needToStart = !ConfigUtils.isPropertyPresent(URL_CONFIG_KEY); + if (!needToStart) { + log.debug("Not starting devservices for default Vault client as url have been provided"); + return null; + } + + String token = RandomStringUtils.randomAlphanumeric(10); + + DockerImageName dockerImageName = DockerImageName.parse(devServicesConfig.imageName.orElse(VAULT_IMAGE)) + .asCompatibleSubstituteFor(VAULT_IMAGE); + FixedPortVaultContainer vaultContainer = new FixedPortVaultContainer(dockerImageName, devServicesConfig.port) + .withVaultToken(token); + + if (devServicesConfig.transitEnabled) { + vaultContainer.withInitCommand("secrets enable transit"); + } + + if (devServicesConfig.pkiEnabled) { + vaultContainer.withInitCommand("secrets enable pki"); + } + + vaultContainer.start(); + + String url = "http://" + vaultContainer.getHost() + ":" + vaultContainer.getPort(); + return new StartResult(url, token, + new Closeable() { + @Override + public void close() { + vaultContainer.close(); + } + }); + } + + private static class StartResult { + private final String url; + private final String clientToken; + private final Closeable closeable; + + public StartResult(String url, String clientToken, Closeable closeable) { + this.url = url; + this.clientToken = clientToken; + this.closeable = closeable; + } + } + + private static class FixedPortVaultContainer extends VaultContainer { + OptionalInt fixedExposedPort; + + public FixedPortVaultContainer(DockerImageName dockerImageName, OptionalInt fixedExposedPort) { + super(dockerImageName); + this.fixedExposedPort = fixedExposedPort; + } + + @Override + protected void configure() { + super.configure(); + if (fixedExposedPort.isPresent()) { + addFixedExposedPort(fixedExposedPort.getAsInt(), VAULT_EXPOSED_PORT); + } else { + addExposedPort(VAULT_EXPOSED_PORT); + } + } + + public int getPort() { + if (fixedExposedPort.isPresent()) { + return fixedExposedPort.getAsInt(); + } + return super.getMappedPort(VAULT_EXPOSED_PORT); + } + } +} diff --git a/extensions/vault/pom.xml b/extensions/vault/pom.xml index 2afd7d5acecdc..ff76595eebd7d 100644 --- a/extensions/vault/pom.xml +++ b/extensions/vault/pom.xml @@ -15,6 +15,7 @@ pom deployment + deployment-spi runtime model diff --git a/extensions/vault/runtime/src/main/java/io/quarkus/vault/runtime/VaultVersions.java b/extensions/vault/runtime/src/main/java/io/quarkus/vault/runtime/VaultVersions.java new file mode 100644 index 0000000000000..e298792b02f2e --- /dev/null +++ b/extensions/vault/runtime/src/main/java/io/quarkus/vault/runtime/VaultVersions.java @@ -0,0 +1,7 @@ +package io.quarkus.vault.runtime; + +public class VaultVersions { + + public static final String VAULT_TEST_VERSION = "1.7.1"; + +} diff --git a/extensions/vault/runtime/src/main/java/io/quarkus/vault/runtime/config/DevServicesConfig.java b/extensions/vault/runtime/src/main/java/io/quarkus/vault/runtime/config/DevServicesConfig.java new file mode 100644 index 0000000000000..8ac8a3cc06e90 --- /dev/null +++ b/extensions/vault/runtime/src/main/java/io/quarkus/vault/runtime/config/DevServicesConfig.java @@ -0,0 +1,76 @@ +package io.quarkus.vault.runtime.config; + +import java.util.Objects; +import java.util.Optional; +import java.util.OptionalInt; + +import io.quarkus.runtime.annotations.ConfigGroup; +import io.quarkus.runtime.annotations.ConfigItem; + +@ConfigGroup +public class DevServicesConfig { + + /** + * If DevServices has been explicitly enabled or disabled. DevServices is generally enabled + * by default, unless there is an existing configuration present. + *

+ * When DevServices is enabled Quarkus will attempt to automatically configure and start + * a vault instance when running in Dev or Test mode and when Docker is running. + */ + @ConfigItem(defaultValue = "true") + public boolean enabled; + + /** + * The container image name to use, for container based DevServices providers. + */ + @ConfigItem + public Optional imageName; + + /** + * Optional fixed port the dev service will listen to. + *

+ * If not defined, the port will be chosen randomly. + */ + @ConfigItem + public OptionalInt port; + + /** + * Should the Transit secret engine be enabled + */ + @ConfigItem(defaultValue = "false") + public boolean transitEnabled; + + /** + * Should the PKI secret engine be enabled + */ + @ConfigItem(defaultValue = "false") + public boolean pkiEnabled; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + DevServicesConfig that = (DevServicesConfig) o; + return enabled == that.enabled && Objects.equals(imageName, + that.imageName) && Objects.equals(port, + that.port); + } + + @Override + public int hashCode() { + return Objects.hash(enabled, imageName, port); + } + + @Override + public String toString() { + return "DevServicesConfig{" + + "enabled=" + enabled + + ", imageName=" + imageName + + ", port=" + port + + '}'; + } +} diff --git a/extensions/vault/runtime/src/main/java/io/quarkus/vault/runtime/config/VaultBuildTimeConfig.java b/extensions/vault/runtime/src/main/java/io/quarkus/vault/runtime/config/VaultBuildTimeConfig.java index c821f3c73df60..77e4355701b05 100644 --- a/extensions/vault/runtime/src/main/java/io/quarkus/vault/runtime/config/VaultBuildTimeConfig.java +++ b/extensions/vault/runtime/src/main/java/io/quarkus/vault/runtime/config/VaultBuildTimeConfig.java @@ -15,10 +15,17 @@ public class VaultBuildTimeConfig { @ConfigDocSection public HealthConfig health; + /** + * Dev services configuration. + */ + @ConfigItem + public DevServicesConfig devservices; + @Override public String toString() { return "VaultBuildTimeConfig{" + "health=" + health + + ", devservices=" + devservices + '}'; } } diff --git a/test-framework/junit5/pom.xml b/test-framework/junit5/pom.xml index ca34c2344f4b1..4f87c5e52a002 100644 --- a/test-framework/junit5/pom.xml +++ b/test-framework/junit5/pom.xml @@ -56,6 +56,10 @@ io.quarkus quarkus-redis-client-deployment-spi + + io.quarkus + quarkus-vault-deployment-spi + com.thoughtworks.xstream xstream diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/NativeDevServicesHandler.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/NativeDevServicesHandler.java index 1300cecc4c74d..37a3424e3db8b 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/NativeDevServicesHandler.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/NativeDevServicesHandler.java @@ -7,6 +7,7 @@ import io.quarkus.datasource.deployment.spi.DevServicesDatasourceResultBuildItem; import io.quarkus.mongodb.deployment.devservices.DevServicesMongoResultBuildItem; import io.quarkus.redis.client.deployment.devservices.DevServicesRedisResultBuildItem; +import io.quarkus.vault.deployment.devservices.DevServicesVaultResultBuildItem; public class NativeDevServicesHandler implements BiConsumer { @Override @@ -56,5 +57,13 @@ public void accept(Object o, BuildResult buildResult) { } } } + + DevServicesVaultResultBuildItem vaultDevServices = buildResult.consumeOptional(DevServicesVaultResultBuildItem.class); + if (vaultDevServices != null) { + Map properties = vaultDevServices.getProperties(); + for (Map.Entry entry : properties.entrySet()) { + propertyConsumer.accept(entry.getKey(), entry.getValue()); + } + } } } diff --git a/test-framework/vault/src/main/java/io/quarkus/vault/test/VaultTestExtension.java b/test-framework/vault/src/main/java/io/quarkus/vault/test/VaultTestExtension.java index a9dfb4832e1e5..33b33f608efc2 100644 --- a/test-framework/vault/src/main/java/io/quarkus/vault/test/VaultTestExtension.java +++ b/test-framework/vault/src/main/java/io/quarkus/vault/test/VaultTestExtension.java @@ -48,6 +48,7 @@ import io.quarkus.vault.VaultException; import io.quarkus.vault.VaultKVSecretEngine; import io.quarkus.vault.runtime.VaultConfigHolder; +import io.quarkus.vault.runtime.VaultVersions; import io.quarkus.vault.runtime.client.VaultClientException; import io.quarkus.vault.runtime.client.backend.VaultInternalSystemBackend; import io.quarkus.vault.runtime.client.dto.sys.VaultInitResponse; @@ -244,7 +245,7 @@ public void start() throws InterruptedException, IOException { } private String getVaultImage() { - return "vault:1.6.3"; + return "vault:" + VaultVersions.VAULT_TEST_VERSION; } private void initVault() throws InterruptedException, IOException { From 6eb79cc47d019547a4f74c3f27f00f9b7a6f1382 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Mon, 17 May 2021 10:16:35 +0300 Subject: [PATCH 0103/2077] Support Kotlin enums as params in RESTEasy Reactive methods Fixes: #17251 --- .../common/processor/EndpointIndexer.java | 10 +++++ .../resteasy/reactive/kotlin/EnumEndpoint.kt | 16 ++++++++ .../it/resteasy/reactive/kotlin/State.kt | 7 ++++ .../it/resteasy/reactive/kotlin/EnumTest.kt | 40 +++++++++++++++++++ 4 files changed, 73 insertions(+) create mode 100644 integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/EnumEndpoint.kt create mode 100644 integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/State.kt create mode 100644 integration-tests/resteasy-reactive-kotlin/standard/src/test/kotlin/io/quarkus/it/resteasy/reactive/kotlin/EnumTest.kt diff --git a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java index 523b27228c10a..8fbea0f57b7b5 100644 --- a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java +++ b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java @@ -81,6 +81,7 @@ import org.jboss.jandex.Type; import org.jboss.jandex.Type.Kind; import org.jboss.jandex.TypeVariable; +import org.jboss.jandex.WildcardType; import org.jboss.logging.Logger; import org.jboss.resteasy.reactive.common.ResteasyReactiveConfig; import org.jboss.resteasy.reactive.common.model.InjectableBean; @@ -718,6 +719,15 @@ protected static String toClassName(Type indexType, ClassInfo currentClass, Clas return indexType.asParameterizedType().name().toString(); case ARRAY: return indexType.asArrayType().name().toString(); + case WILDCARD_TYPE: + WildcardType wildcardType = indexType.asWildcardType(); + Type extendsBound = wildcardType.extendsBound(); + if (extendsBound.name().equals(ResteasyReactiveDotNames.OBJECT)) { + // this is a super bound type that we don't support + throw new RuntimeException("Cannot handle wildcard type " + indexType); + } + // this is an extend bound type, so we just user the bound + return wildcardType.name().toString(); case TYPE_VARIABLE: TypeVariable typeVariable = indexType.asTypeVariable(); if (typeVariable.bounds().isEmpty()) { diff --git a/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/EnumEndpoint.kt b/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/EnumEndpoint.kt new file mode 100644 index 0000000000000..01836dfb03ec9 --- /dev/null +++ b/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/EnumEndpoint.kt @@ -0,0 +1,16 @@ +package io.quarkus.it.resteasy.reactive.kotlin + +import javax.ws.rs.GET +import javax.ws.rs.Path +import javax.ws.rs.Produces +import javax.ws.rs.QueryParam +import javax.ws.rs.core.MediaType + +@Path("enum") +class EnumEndpoint { + + @GET + @Produces(MediaType.TEXT_PLAIN) + fun test(@QueryParam(value = "state") states: List) = "States: $states" + +} diff --git a/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/State.kt b/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/State.kt new file mode 100644 index 0000000000000..1791c2ae5f90d --- /dev/null +++ b/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/State.kt @@ -0,0 +1,7 @@ +package io.quarkus.it.resteasy.reactive.kotlin + +enum class State { + State1, + State2, + State3 +} diff --git a/integration-tests/resteasy-reactive-kotlin/standard/src/test/kotlin/io/quarkus/it/resteasy/reactive/kotlin/EnumTest.kt b/integration-tests/resteasy-reactive-kotlin/standard/src/test/kotlin/io/quarkus/it/resteasy/reactive/kotlin/EnumTest.kt new file mode 100644 index 0000000000000..0e57aa5b35321 --- /dev/null +++ b/integration-tests/resteasy-reactive-kotlin/standard/src/test/kotlin/io/quarkus/it/resteasy/reactive/kotlin/EnumTest.kt @@ -0,0 +1,40 @@ +package io.quarkus.it.resteasy.reactive.kotlin + +import io.quarkus.test.junit.QuarkusTest +import io.restassured.RestAssured.given +import org.hamcrest.Matchers.equalTo +import org.junit.jupiter.api.Test + +@QuarkusTest +class EnumTest { + + @Test + fun testNoStates() { + given() + .`when`() + .get("/enum") + .then() + .statusCode(200) + .body(equalTo("States: []")) + } + + @Test + fun testSingleState() { + given() + .`when`() + .get("/enum?state=State1") + .then() + .statusCode(200) + .body(equalTo("States: [State1]")) + } + + @Test + fun testMultipleStates() { + given() + .`when`() + .get("/enum?state=State1&state=State2&state=State3") + .then() + .statusCode(200) + .body(equalTo("States: [State1, State2, State3]")) + } +} From f06cca4dca498f115f713d80dc6e5e5cedcfabe0 Mon Sep 17 00:00:00 2001 From: Falko Modler Date: Mon, 17 May 2021 17:22:37 +0200 Subject: [PATCH 0104/2077] Java 16+: Don't exec AllConfigGenerator as long as --add-opens is required --- docs/pom.xml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs/pom.xml b/docs/pom.xml index 8bfd7e7878c6b..33333a8483e59 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -2853,5 +2853,26 @@ + + jdk16-workarounds + + [16,) + + + + + + org.codehaus.mojo + exec-maven-plugin + + true + + + + + From 7bc6edcae8eb9a95675eef08ad1fead404dfae17 Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Mon, 17 May 2021 18:20:10 +0100 Subject: [PATCH 0105/2077] Support OidcClient refresh_token mode only --- .../quarkus/oidc/client/OidcClientConfig.java | 13 +++++- .../oidc/client/runtime/OidcClientImpl.java | 4 ++ .../client/runtime/OidcClientRecorder.java | 40 ++++++++++--------- .../oidc-client-wiremock/pom.xml | 17 ++++++++ .../quarkus/it/keycloak/FrontendResource.java | 15 +++++++ .../src/main/resources/application.properties | 7 ++++ .../KeycloakRealmResourceManager.java | 8 ++++ .../quarkus/it/keycloak/OidcClientTest.java | 9 +++++ 8 files changed, 94 insertions(+), 19 deletions(-) diff --git a/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/OidcClientConfig.java b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/OidcClientConfig.java index 1e86094bf2a87..832a012974abb 100644 --- a/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/OidcClientConfig.java +++ b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/OidcClientConfig.java @@ -63,7 +63,18 @@ public static enum Type { * 'urn:ietf:params:oauth:grant-type:token-exchange' grant requiring an OIDC client authentication as well as * at least 'subject_token' parameter which must be passed to OidcClient at the token request time. */ - EXCHANGE("urn:ietf:params:oauth:grant-type:token-exchange"); + EXCHANGE("urn:ietf:params:oauth:grant-type:token-exchange"), + + /** + * 'refresh_token' grant requiring an OIDC client authentication and a refresh token. + * Note, OidcClient supports this grant by default if an access token acquisition response contained a refresh + * token. + * However, in some cases, the refresh token is provided out of band, for example, it can be shared between + * several of the confidential client's services, etc. + * If 'quarkus.oidc-client.grant-type' is set to 'refresh' then `OidcClient` will only support refreshing the + * tokens. + */ + REFRESH("refresh_token"); private String grantType; diff --git a/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientImpl.java b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientImpl.java index 24a56c5139d3c..cbeeb1f177009 100644 --- a/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientImpl.java +++ b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientImpl.java @@ -57,6 +57,10 @@ public OidcClientImpl(WebClient client, String tokenRequestUri, String grantType @Override public Uni getTokens(Map additionalGrantParameters) { + if (tokenGrantParams == null) { + throw new OidcClientException( + "Only 'refresh_token' grant is supported, please call OidcClient#refreshTokens method instead"); + } return getJsonResponse(tokenGrantParams, additionalGrantParameters, false); } diff --git a/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientRecorder.java b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientRecorder.java index bc884ba8b6b48..9915fdfbec26f 100644 --- a/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientRecorder.java +++ b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientRecorder.java @@ -141,25 +141,29 @@ public OidcClient apply(String tokenRequestUri, Throwable t) { throw new ConfigurationException( "OpenId Connect Provider token endpoint URL is not configured and can not be discovered"); } - MultiMap tokenGrantParams = new MultiMap(io.vertx.core.MultiMap.caseInsensitiveMultiMap()); - String grantType = oidcConfig.grant.getType().getGrantType(); - setGrantClientParams(oidcConfig, tokenGrantParams, grantType); - - if (oidcConfig.getGrantOptions() != null) { - Map grantOptions = oidcConfig.getGrantOptions() - .get(oidcConfig.grant.getType().name().toLowerCase()); - if (grantOptions != null) { - if (oidcConfig.grant.getType() == Grant.Type.PASSWORD) { - // Without this block `password` will be listed first, before `username` - // which is not a technical problem but might affect Wiremock tests or the endpoints - // which expect a specific order. - tokenGrantParams.add(OidcConstants.PASSWORD_GRANT_USERNAME, - grantOptions.get(OidcConstants.PASSWORD_GRANT_USERNAME)); - tokenGrantParams.add(OidcConstants.PASSWORD_GRANT_PASSWORD, - grantOptions.get(OidcConstants.PASSWORD_GRANT_PASSWORD)); - } else { - tokenGrantParams.addAll(grantOptions); + + MultiMap tokenGrantParams = null; + + if (oidcConfig.grant.getType() != Grant.Type.REFRESH) { + tokenGrantParams = new MultiMap(io.vertx.core.MultiMap.caseInsensitiveMultiMap()); + setGrantClientParams(oidcConfig, tokenGrantParams, grantType); + + if (oidcConfig.getGrantOptions() != null) { + Map grantOptions = oidcConfig.getGrantOptions() + .get(oidcConfig.grant.getType().name().toLowerCase()); + if (grantOptions != null) { + if (oidcConfig.grant.getType() == Grant.Type.PASSWORD) { + // Without this block `password` will be listed first, before `username` + // which is not a technical problem but might affect Wiremock tests or the endpoints + // which expect a specific order. + tokenGrantParams.add(OidcConstants.PASSWORD_GRANT_USERNAME, + grantOptions.get(OidcConstants.PASSWORD_GRANT_USERNAME)); + tokenGrantParams.add(OidcConstants.PASSWORD_GRANT_PASSWORD, + grantOptions.get(OidcConstants.PASSWORD_GRANT_PASSWORD)); + } else { + tokenGrantParams.addAll(grantOptions); + } } } } diff --git a/integration-tests/oidc-client-wiremock/pom.xml b/integration-tests/oidc-client-wiremock/pom.xml index c3d37f77cb7fd..0d0aab5da6a42 100644 --- a/integration-tests/oidc-client-wiremock/pom.xml +++ b/integration-tests/oidc-client-wiremock/pom.xml @@ -58,6 +58,23 @@ + + io.quarkus + quarkus-resteasy-mutiny + + + io.quarkus + quarkus-resteasy-mutiny-deployment + ${project.version} + pom + test + + + * + * + + + io.quarkus quarkus-oidc-client-filter diff --git a/integration-tests/oidc-client-wiremock/src/main/java/io/quarkus/it/keycloak/FrontendResource.java b/integration-tests/oidc-client-wiremock/src/main/java/io/quarkus/it/keycloak/FrontendResource.java index 736790ddce0e3..e6f7da8c2d6b2 100644 --- a/integration-tests/oidc-client-wiremock/src/main/java/io/quarkus/it/keycloak/FrontendResource.java +++ b/integration-tests/oidc-client-wiremock/src/main/java/io/quarkus/it/keycloak/FrontendResource.java @@ -3,11 +3,15 @@ import javax.inject.Inject; import javax.ws.rs.GET; import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import org.eclipse.microprofile.rest.client.inject.RestClient; import io.quarkus.oidc.client.NamedOidcClient; +import io.quarkus.oidc.client.OidcClients; import io.quarkus.oidc.client.Tokens; +import io.smallrye.mutiny.Uni; @Path("/frontend") public class FrontendResource { @@ -19,6 +23,9 @@ public class FrontendResource { @NamedOidcClient("non-standard-response") Tokens tokens; + @Inject + OidcClients clients; + @GET @Path("echoToken") public String echoToken() { @@ -30,4 +37,12 @@ public String echoToken() { public String echoTokenNonStandardResponse() { return tokens.getAccessToken() + " " + tokens.getRefreshToken(); } + + @GET + @Path("echoRefreshTokenOnly") + @Produces("text/plain") + public Uni echoRefreshTokenOnly(@QueryParam("refreshToken") String refreshToken) { + return clients.getClient("refresh").refreshTokens(refreshToken) + .onItem().transform(t -> t.getAccessToken()); + } } diff --git a/integration-tests/oidc-client-wiremock/src/main/resources/application.properties b/integration-tests/oidc-client-wiremock/src/main/resources/application.properties index 4a92258f502e0..33370bbd44517 100644 --- a/integration-tests/oidc-client-wiremock/src/main/resources/application.properties +++ b/integration-tests/oidc-client-wiremock/src/main/resources/application.properties @@ -19,6 +19,13 @@ quarkus.oidc-client.non-standard-response.grant.expires-in-property=expiresIn quarkus.oidc-client.non-standard-response.grant-options.password.username=alice quarkus.oidc-client.non-standard-response.grant-options.password.password=alice +quarkus.oidc-client.refresh.auth-server-url=${keycloak.url} +quarkus.oidc-client.refresh.discovery-enabled=false +quarkus.oidc-client.refresh.token-path=/refresh-token-only +quarkus.oidc-client.refresh.client-id=quarkus-app +quarkus.oidc-client.refresh.credentials.secret=secret +quarkus.oidc-client.refresh.grant.type=refresh + io.quarkus.it.keycloak.ProtectedResourceServiceOidcClient/mp-rest/url=http://localhost:8081/protected quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientImpl".min-level=TRACE diff --git a/integration-tests/oidc-client-wiremock/src/test/java/io/quarkus/it/keycloak/KeycloakRealmResourceManager.java b/integration-tests/oidc-client-wiremock/src/test/java/io/quarkus/it/keycloak/KeycloakRealmResourceManager.java index 06c3766e175f1..d239dc5ef7ba9 100644 --- a/integration-tests/oidc-client-wiremock/src/test/java/io/quarkus/it/keycloak/KeycloakRealmResourceManager.java +++ b/integration-tests/oidc-client-wiremock/src/test/java/io/quarkus/it/keycloak/KeycloakRealmResourceManager.java @@ -51,6 +51,14 @@ public Map start() { .withBody( "{\"access_token\":\"access_token_2\", \"expires_in\":4, \"refresh_token\":\"refresh_token_1\"}"))); + server.stubFor(WireMock.post("/refresh-token-only") + .withRequestBody(matching("grant_type=refresh_token&refresh_token=shared_refresh_token")) + .willReturn(WireMock + .aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON) + .withBody( + "{\"access_token\":\"temp_access_token\", \"expires_in\":4}"))); + LOG.infof("Keycloak started in mock mode: %s", server.baseUrl()); Map conf = new HashMap<>(); diff --git a/integration-tests/oidc-client-wiremock/src/test/java/io/quarkus/it/keycloak/OidcClientTest.java b/integration-tests/oidc-client-wiremock/src/test/java/io/quarkus/it/keycloak/OidcClientTest.java index fb65310c930e3..7d4c45df61bd5 100644 --- a/integration-tests/oidc-client-wiremock/src/test/java/io/quarkus/it/keycloak/OidcClientTest.java +++ b/integration-tests/oidc-client-wiremock/src/test/java/io/quarkus/it/keycloak/OidcClientTest.java @@ -61,6 +61,15 @@ public void testEchoTokensNonStandardResponse() { .body(equalTo("access_token_n refresh_token_n")); } + @Test + public void testEchoTokensRefreshTokenOnly() { + RestAssured.given().queryParam("refreshToken", "shared_refresh_token") + .when().get("/frontend/echoRefreshTokenOnly") + .then() + .statusCode(200) + .body(equalTo("temp_access_token")); + } + private void checkLog() { final Path logDirectory = Paths.get(".", "target"); given().await().pollInterval(100, TimeUnit.MILLISECONDS) From 384a9296179579f76c428f18d3ef642e3a1a5b63 Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Mon, 17 May 2021 14:28:39 -0300 Subject: [PATCH 0106/2077] Add configuration reference to Deploying to OpenShift --- docs/src/main/asciidoc/deploying-to-openshift.adoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/src/main/asciidoc/deploying-to-openshift.adoc b/docs/src/main/asciidoc/deploying-to-openshift.adoc index 3c13bf9e6957d..87fb3b2e4ec53 100644 --- a/docs/src/main/asciidoc/deploying-to-openshift.adoc +++ b/docs/src/main/asciidoc/deploying-to-openshift.adoc @@ -395,3 +395,7 @@ quarkus.container-image.registry=image-registry.openshift-image-registry.svc:500 ---- The application can then be deployed to OpenShift Serverless by enabling the standard `quarkus.kubernetes.deploy=true` property. + +== Configuration Reference + +include::{generated-dir}/config/quarkus-openshift-openshift-config.adoc[opts=optional, leveloffset=+1] From 9efc6398de5158a7678369de820388cfdbd50f97 Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Mon, 17 May 2021 15:07:43 -0300 Subject: [PATCH 0107/2077] Use StandardCharsets.UTF_8 where appropriate --- .../quarkus/container/image/s2i/deployment/PackageUtil.java | 3 ++- .../main/java/io/quarkus/qute/runtime/EngineProducer.java | 4 ++-- .../maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java | 6 +++--- .../src/test/java/io/quarkus/maven/it/RemoteDevMojoIT.java | 4 ++-- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/extensions/container-image/container-image-s2i/deployment/src/main/java/io/quarkus/container/image/s2i/deployment/PackageUtil.java b/extensions/container-image/container-image-s2i/deployment/src/main/java/io/quarkus/container/image/s2i/deployment/PackageUtil.java index c66340af4c797..eb0f28c09b691 100644 --- a/extensions/container-image/container-image-s2i/deployment/src/main/java/io/quarkus/container/image/s2i/deployment/PackageUtil.java +++ b/extensions/container-image/container-image-s2i/deployment/src/main/java/io/quarkus/container/image/s2i/deployment/PackageUtil.java @@ -7,6 +7,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; @@ -32,7 +33,7 @@ public class PackageUtil { protected static final String DOCKER_PREFIX = "docker-"; protected static final String BZIP2_SUFFIX = ".tar.bzip2"; - private static final Charset UTF_8 = Charset.forName("UTF-8"); + private static final Charset UTF_8 = StandardCharsets.UTF_8; public static File packageFile(String path) { return packageFile(path, null); diff --git a/extensions/qute/runtime/src/main/java/io/quarkus/qute/runtime/EngineProducer.java b/extensions/qute/runtime/src/main/java/io/quarkus/qute/runtime/EngineProducer.java index 3b881c7180bc4..d6dedbd3b4e57 100644 --- a/extensions/qute/runtime/src/main/java/io/quarkus/qute/runtime/EngineProducer.java +++ b/extensions/qute/runtime/src/main/java/io/quarkus/qute/runtime/EngineProducer.java @@ -5,7 +5,7 @@ import java.io.Reader; import java.lang.reflect.InvocationTargetException; import java.net.URL; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Optional; @@ -223,7 +223,7 @@ public ResourceTemplateLocation(URL resource, Variant variant) { @Override public Reader read() { try { - return new InputStreamReader(resource.openStream(), Charset.forName("utf-8")); + return new InputStreamReader(resource.openStream(), StandardCharsets.UTF_8); } catch (IOException e) { return null; } diff --git a/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java b/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java index 4378313242414..82ce10529fc4d 100644 --- a/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java +++ b/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java @@ -15,7 +15,7 @@ import java.io.FileReader; import java.io.IOException; import java.io.StringWriter; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Arrays; @@ -632,7 +632,7 @@ public void testThatTheApplicationIsReloadedOnNewResource() throws MavenInvocati " return \"bar\";\n" + " }\n" + "}\n"; - FileUtils.write(source, myNewResource, Charset.forName("UTF-8")); + FileUtils.write(source, myNewResource, StandardCharsets.UTF_8); // Wait until we get "bar" await() @@ -666,7 +666,7 @@ public void testThatClassFileAreCleanedUp() throws MavenInvocationException, IOE " return \"to be deleted\";\n" + " }\n" + "}"; - FileUtils.write(source, classDeletionResource, Charset.forName("UTF-8")); + FileUtils.write(source, classDeletionResource, StandardCharsets.UTF_8); runAndCheck(); // Wait until source file is compiled diff --git a/integration-tests/maven/src/test/java/io/quarkus/maven/it/RemoteDevMojoIT.java b/integration-tests/maven/src/test/java/io/quarkus/maven/it/RemoteDevMojoIT.java index 429aa61401664..5c8887b6e6c55 100644 --- a/integration-tests/maven/src/test/java/io/quarkus/maven/it/RemoteDevMojoIT.java +++ b/integration-tests/maven/src/test/java/io/quarkus/maven/it/RemoteDevMojoIT.java @@ -5,7 +5,7 @@ import java.io.File; import java.io.IOException; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collections; import java.util.UUID; @@ -82,7 +82,7 @@ public void testThatTheApplicationIsReloadedOnNewResource() throws MavenInvocati " return \"bar\";\n" + " }\n" + "}\n"; - FileUtils.write(source, myNewResource, Charset.forName("UTF-8")); + FileUtils.write(source, myNewResource, StandardCharsets.UTF_8); // Wait until we get "bar" await() From 8e320ce99d6a77436ca875abb742c9add6daa630 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Mon, 17 May 2021 21:59:00 +0300 Subject: [PATCH 0108/2077] Fix typo in RESTEasy Reactive Serialisers --- .../resteasy/reactive/client/impl/ClientSerialisers.java | 4 ++-- .../jboss/resteasy/reactive/common/core/Serialisers.java | 8 ++++---- .../resteasy/reactive/server/core/ServerSerialisers.java | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientSerialisers.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientSerialisers.java index d85b3eed941eb..cb21b80e096be 100644 --- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientSerialisers.java +++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientSerialisers.java @@ -133,12 +133,12 @@ public static Object invokeClientReader(Annotation[] annotations, Class entit } @Override - public BuiltinWriter[] getBultinWriters() { + public BuiltinWriter[] getBuiltinWriters() { return BUILTIN_WRITERS; } @Override - public BuiltinReader[] getBultinReaders() { + public BuiltinReader[] getBuiltinReaders() { return BUILTIN_READERS; } } diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/core/Serialisers.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/core/Serialisers.java index 2b8430fb36fc4..3b809cf66802b 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/core/Serialisers.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/core/Serialisers.java @@ -219,12 +219,12 @@ private void writerLookup(RuntimeType runtimeType, List mt, List writer; try { @@ -241,7 +241,7 @@ public void registerBuiltins(RuntimeType constraint) { addWriter(builtinWriter.entityClass, resourceWriter); } } - for (BuiltinReader builtinReader : getBultinReaders()) { + for (BuiltinReader builtinReader : getBuiltinReaders()) { if (builtinReader.constraint == null || builtinReader.constraint == constraint) { MessageBodyReader reader; try { diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ServerSerialisers.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ServerSerialisers.java index 82c461b48ce53..33703fc1a098b 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ServerSerialisers.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ServerSerialisers.java @@ -396,12 +396,12 @@ public NoMediaTypeResult findWriterNoMediaType(ResteasyReactiveRequestContext re } @Override - public BuiltinWriter[] getBultinWriters() { + public BuiltinWriter[] getBuiltinWriters() { return BUILTIN_WRITERS; } @Override - public BuiltinReader[] getBultinReaders() { + public BuiltinReader[] getBuiltinReaders() { return BUILTIN_READERS; } From 6cef88df18452dece1ccd526368fc885edec4e7f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 May 2021 19:01:21 +0000 Subject: [PATCH 0109/2077] Bump junit-jupiter from 5.7.1 to 5.7.2 in /devtools/gradle Bumps [junit-jupiter](https://github.com/junit-team/junit5) from 5.7.1 to 5.7.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.7.1...r5.7.2) Signed-off-by: dependabot[bot] --- devtools/gradle/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devtools/gradle/build.gradle b/devtools/gradle/build.gradle index de4176961da1e..1b84d4a07aee3 100644 --- a/devtools/gradle/build.gradle +++ b/devtools/gradle/build.gradle @@ -37,7 +37,7 @@ dependencies { testImplementation "io.quarkus:quarkus-project-core-extension-codestarts:${version}" testImplementation 'org.mockito:mockito-core:3.10.0' testImplementation 'org.assertj:assertj-core:3.19.0' - testImplementation 'org.junit.jupiter:junit-jupiter:5.7.1' + testImplementation 'org.junit.jupiter:junit-jupiter:5.7.2' testImplementation 'org.awaitility:awaitility:4.1.0' testImplementation "io.quarkus:quarkus-devmode-test-utils:${version}" testImplementation gradleTestKit() From 4f120a7b59c31fd6f7ce488957aa33420630ae17 Mon Sep 17 00:00:00 2001 From: Phillip Kruger Date: Mon, 17 May 2021 21:03:40 +0200 Subject: [PATCH 0110/2077] Upgrade SmallRye GraphQL to 1.2.0 (Initial subscription support) Signed-off-by: Phillip Kruger --- bom/application/pom.xml | 2 +- docs/src/main/asciidoc/smallrye-graphql.adoc | 47 +++++ .../deployment/SmallRyeGraphQLProcessor.java | 18 +- .../graphql/deployment/SecurityTest.java | 2 +- .../SmallRyeGraphQLAbstractHandler.java | 85 ++++++++ .../SmallRyeGraphQLExecutionHandler.java | 72 ++----- .../runtime/SmallRyeGraphQLRecorder.java | 27 ++- .../SmallRyeGraphQLSubscriptionHandler.java | 184 ++++++++++++++++++ .../deployment/HttpRootPathBuildItem.java | 20 ++ 9 files changed, 380 insertions(+), 77 deletions(-) create mode 100644 extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLAbstractHandler.java create mode 100644 extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLSubscriptionHandler.java diff --git a/bom/application/pom.xml b/bom/application/pom.xml index b80a9d3893a60..8285a4dc51b71 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -46,7 +46,7 @@ 3.0.1 3.0.1 2.1.4 - 1.1.0 + 1.2.0 2.0.0 5.0.0 3.1.1 diff --git a/docs/src/main/asciidoc/smallrye-graphql.adoc b/docs/src/main/asciidoc/smallrye-graphql.adoc index 965f1919ba75e..74d92490ded9d 100644 --- a/docs/src/main/asciidoc/smallrye-graphql.adoc +++ b/docs/src/main/asciidoc/smallrye-graphql.adoc @@ -646,6 +646,7 @@ This can easily be a server side generated field that the client may require. Let's now try deleting an entry: +[source,graphql] ---- mutation DeleteHero { deleteHero(id :3){ @@ -658,6 +659,52 @@ mutation DeleteHero { Similar to the `createHero` mutation method we also retrieve the `name` and `surname` of the hero we have deleted which is defined in `{ }`. +== Subscriptions + +Subscriptions allows you to subscribe to a query. It allows you to receive events. + +NOTE: Subscription is currently still considered experimental. + +Example: We want to know when new Heroes are being created: + +[source,java] +---- + + BroadcastProcessor processor = BroadcastProcessor.create(); // <1> + + @Mutation + public Hero createHero(Hero hero) { + service.addHero(hero); + processor.onNext(hero); // <2> + return hero; + } + + @Subscription + public Multi heroCreated(){ + return processor; // <3> + } + +---- + +<1> The `Multi` processor that will broadcast any new Heros +<2> When adding a new Hero, also broadcast it +<3> Make the stream available in the schema and as a WebSocket during runtime + + +Any client that now connect to the `/graphql` WebSocket connection will receive events on new Heroes being created: + +[source,graphql] +---- + +subscription ListenForNewHeroes { + heroCreated { + name + surname + } +} + +---- + == Creating Queries by fields Queries can also be done on individual fields. For example, let's diff --git a/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java b/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java index 4ae46fae0450a..e419c9f103bbf 100644 --- a/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java +++ b/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java @@ -59,6 +59,7 @@ import io.smallrye.graphql.cdi.config.ConfigKey; import io.smallrye.graphql.cdi.config.GraphQLConfig; import io.smallrye.graphql.cdi.producer.GraphQLProducer; +import io.smallrye.graphql.cdi.producer.SmallRyeContextAccessorProxy; import io.smallrye.graphql.schema.Annotations; import io.smallrye.graphql.schema.SchemaBuilder; import io.smallrye.graphql.schema.model.Argument; @@ -135,8 +136,7 @@ void additionalBean(BuildProducer additionalBeanProduce additionalBeanProducer.produce(AdditionalBeanBuildItem.builder() .addBeanClass(GraphQLConfig.class) .addBeanClass(GraphQLProducer.class) - // TODO - MP4 - Require GraphQL Update - //.addBeanClass(SmallRyeContextAccessorProxy.class) + .addBeanClass(SmallRyeContextAccessorProxy.class) .setUnremovable().build()); } @@ -210,7 +210,8 @@ void buildExecutionEndpoint( ShutdownContextBuildItem shutdownContext, LaunchModeBuildItem launchMode, BodyHandlerBuildItem bodyHandlerBuildItem, - SmallRyeGraphQLConfig graphQLConfig) { + SmallRyeGraphQLConfig graphQLConfig, + BeanContainerBuildItem beanContainer) { /* * Ugly Hack @@ -225,8 +226,17 @@ void buildExecutionEndpoint( recorder.setupClDevMode(shutdownContext); } - Boolean allowGet = ConfigProvider.getConfig().getOptionalValue(ConfigKey.ALLOW_GET, boolean.class).orElse(false); + // Subscriptions + Handler subscriptionHandler = recorder + .subscriptionHandler(beanContainer.getValue(), graphQLInitializedBuildItem.getInitialized()); + routeProducer.produce(httpRootPathBuildItem.routeBuilder() + .orderedRoute(graphQLConfig.rootPath, Integer.MIN_VALUE) + .handler(subscriptionHandler) + .build()); + + // Queries and Mutations + Boolean allowGet = ConfigProvider.getConfig().getOptionalValue(ConfigKey.ALLOW_GET, boolean.class).orElse(false); Handler executionHandler = recorder.executionHandler(graphQLInitializedBuildItem.getInitialized(), allowGet); routeProducer.produce(httpRootPathBuildItem.routeBuilder() diff --git a/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/SecurityTest.java b/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/SecurityTest.java index 6f9ed1d431c78..06f39ebc103d3 100644 --- a/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/SecurityTest.java +++ b/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/SecurityTest.java @@ -95,7 +95,7 @@ public void testUnauthorizedForSource() { .body("data.foo.bonusBar", nullValue()); } - static class Foo { + public static class Foo { private String message; diff --git a/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLAbstractHandler.java b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLAbstractHandler.java new file mode 100644 index 0000000000000..648dfdb1d5574 --- /dev/null +++ b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLAbstractHandler.java @@ -0,0 +1,85 @@ +package io.quarkus.smallrye.graphql.runtime; + +import java.io.StringReader; + +import javax.json.Json; +import javax.json.JsonBuilderFactory; +import javax.json.JsonObject; +import javax.json.JsonReader; +import javax.json.JsonReaderFactory; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.ManagedContext; +import io.quarkus.security.identity.CurrentIdentityAssociation; +import io.quarkus.security.identity.SecurityIdentity; +import io.quarkus.vertx.http.runtime.CurrentVertxRequest; +import io.quarkus.vertx.http.runtime.security.QuarkusHttpUser; +import io.smallrye.graphql.execution.ExecutionService; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; + +/** + * Handler that does the execution of GraphQL Requests + */ +public abstract class SmallRyeGraphQLAbstractHandler implements Handler { + + private final CurrentIdentityAssociation currentIdentityAssociation; + private final CurrentVertxRequest currentVertxRequest; + + private volatile ExecutionService executionService; + + private static final JsonBuilderFactory jsonObjectFactory = Json.createBuilderFactory(null); + private static final JsonReaderFactory jsonReaderFactory = Json.createReaderFactory(null); + + public SmallRyeGraphQLAbstractHandler( + CurrentIdentityAssociation currentIdentityAssociation, + CurrentVertxRequest currentVertxRequest) { + + this.currentIdentityAssociation = currentIdentityAssociation; + this.currentVertxRequest = currentVertxRequest; + } + + @Override + public void handle(final RoutingContext ctx) { + ManagedContext requestContext = Arc.container().requestContext(); + if (requestContext.isActive()) { + handleWithIdentity(ctx); + } else { + try { + requestContext.activate(); + handleWithIdentity(ctx); + } finally { + requestContext.terminate(); + } + } + } + + private void handleWithIdentity(final RoutingContext ctx) { + if (currentIdentityAssociation != null) { + QuarkusHttpUser existing = (QuarkusHttpUser) ctx.user(); + if (existing != null) { + SecurityIdentity identity = existing.getSecurityIdentity(); + currentIdentityAssociation.setIdentity(identity); + } else { + currentIdentityAssociation.setIdentity(QuarkusHttpUser.getSecurityIdentity(ctx, null)); + } + } + currentVertxRequest.setCurrent(ctx); + doHandle(ctx); + } + + protected abstract void doHandle(final RoutingContext ctx); + + protected JsonObject inputToJsonObject(String input) { + try (JsonReader jsonReader = jsonReaderFactory.createReader(new StringReader(input))) { + return jsonReader.readObject(); + } + } + + protected ExecutionService getExecutionService() { + if (this.executionService == null) { + this.executionService = Arc.container().instance(ExecutionService.class).get(); + } + return this.executionService; + } +} diff --git a/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLExecutionHandler.java b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLExecutionHandler.java index 47ff9ca1dc828..568c1d38be06e 100644 --- a/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLExecutionHandler.java +++ b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLExecutionHandler.java @@ -3,7 +3,6 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.StringReader; -import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.List; @@ -14,17 +13,10 @@ import javax.json.JsonObjectBuilder; import javax.json.JsonReader; import javax.json.JsonReaderFactory; -import javax.json.JsonWriter; -import javax.json.JsonWriterFactory; -import io.quarkus.arc.Arc; -import io.quarkus.arc.ManagedContext; import io.quarkus.security.identity.CurrentIdentityAssociation; -import io.quarkus.security.identity.SecurityIdentity; import io.quarkus.vertx.http.runtime.CurrentVertxRequest; -import io.quarkus.vertx.http.runtime.security.QuarkusHttpUser; -import io.smallrye.graphql.execution.ExecutionService; -import io.vertx.core.Handler; +import io.smallrye.graphql.execution.ExecutionResponse; import io.vertx.core.buffer.Buffer; import io.vertx.core.http.HttpHeaders; import io.vertx.core.http.HttpServerRequest; @@ -34,51 +26,23 @@ /** * Handler that does the execution of GraphQL Requests */ -public class SmallRyeGraphQLExecutionHandler implements Handler { - private static boolean allowGet = false; +public class SmallRyeGraphQLExecutionHandler extends SmallRyeGraphQLAbstractHandler { + private boolean allowGet = false; private static final String QUERY = "query"; private static final String VARIABLES = "variables"; private static final String OK = "OK"; - private volatile ExecutionService executionService; - private final CurrentIdentityAssociation currentIdentityAssociation; - private final CurrentVertxRequest currentVertxRequest; + private static final JsonBuilderFactory jsonObjectFactory = Json.createBuilderFactory(null); private static final JsonReaderFactory jsonReaderFactory = Json.createReaderFactory(null); - private static final JsonWriterFactory jsonWriterFactory = Json.createWriterFactory(null); public SmallRyeGraphQLExecutionHandler(boolean allowGet, CurrentIdentityAssociation currentIdentityAssociation, CurrentVertxRequest currentVertxRequest) { - SmallRyeGraphQLExecutionHandler.allowGet = allowGet; - this.currentIdentityAssociation = currentIdentityAssociation; - this.currentVertxRequest = currentVertxRequest; + super(currentIdentityAssociation, currentVertxRequest); + this.allowGet = allowGet; } @Override - public void handle(final RoutingContext ctx) { - ManagedContext requestContext = Arc.container().requestContext(); - if (requestContext.isActive()) { - doHandle(ctx); - } else { - try { - requestContext.activate(); - doHandle(ctx); - } finally { - requestContext.terminate(); - } - } - } - - private void doHandle(final RoutingContext ctx) { - if (currentIdentityAssociation != null) { - QuarkusHttpUser existing = (QuarkusHttpUser) ctx.user(); - if (existing != null) { - SecurityIdentity identity = existing.getSecurityIdentity(); - currentIdentityAssociation.setIdentity(identity); - } else { - currentIdentityAssociation.setIdentity(QuarkusHttpUser.getSecurityIdentity(ctx, null)); - } - } - currentVertxRequest.setCurrent(ctx); + protected void doHandle(final RoutingContext ctx) { HttpServerRequest request = ctx.request(); HttpServerResponse response = ctx.response(); @@ -96,7 +60,7 @@ private void doHandle(final RoutingContext ctx) { handleGet(response, ctx); break; default: - response.setStatusCode(405).end(); + ctx.next(); break; } } @@ -173,16 +137,9 @@ private String doRequest(final byte[] body) { } private String doRequest(JsonObject jsonInput) { - JsonObject outputJson = getExecutionService().execute(jsonInput); - if (outputJson != null) { - try (StringWriter output = new StringWriter(); - final JsonWriter jsonWriter = jsonWriterFactory.createWriter(output)) { - jsonWriter.writeObject(outputJson); - output.flush(); - return output.toString(); - } catch (IOException ex) { - throw new RuntimeException(ex); - } + ExecutionResponse executionResponse = getExecutionService().execute(jsonInput); + if (executionResponse != null) { + return executionResponse.getExecutionResultAsString(); } return null; } @@ -196,11 +153,4 @@ private static JsonObject toJsonObject(String jsonString) { return jsonReader.readObject(); } } - - private ExecutionService getExecutionService() { - if (this.executionService == null) { - this.executionService = Arc.container().instance(ExecutionService.class).get(); - } - return this.executionService; - } } diff --git a/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLRecorder.java b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLRecorder.java index 4ed8144b50219..b1b517627c5cf 100644 --- a/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLRecorder.java +++ b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLRecorder.java @@ -32,21 +32,19 @@ public RuntimeValue createExecutionService(BeanContainer beanContainer, public Handler executionHandler(RuntimeValue initialized, boolean allowGet) { if (initialized.getValue()) { - Instance identityAssociations = CDI.current() - .select(CurrentIdentityAssociation.class); - CurrentIdentityAssociation association; - if (identityAssociations.isResolvable()) { - association = identityAssociations.get(); - } else { - association = null; - } - CurrentVertxRequest currentVertxRequest = CDI.current().select(CurrentVertxRequest.class).get(); - return new SmallRyeGraphQLExecutionHandler(allowGet, association, currentVertxRequest); + return new SmallRyeGraphQLExecutionHandler(allowGet, getCurrentIdentityAssociation(), + CDI.current().select(CurrentVertxRequest.class).get()); } else { return new SmallRyeGraphQLNoEndpointHandler(); } } + public Handler subscriptionHandler(BeanContainer beanContainer, RuntimeValue initialized) { + GraphQLConfig config = beanContainer.instance(GraphQLConfig.class); + return new SmallRyeGraphQLSubscriptionHandler(config, getCurrentIdentityAssociation(), + CDI.current().select(CurrentVertxRequest.class).get()); + } + public Handler schemaHandler(RuntimeValue initialized) { if (initialized.getValue()) { return new SmallRyeGraphQLSchemaHandler(); @@ -83,4 +81,13 @@ public void accept(Route route) { } }; } + + private CurrentIdentityAssociation getCurrentIdentityAssociation() { + Instance identityAssociations = CDI.current() + .select(CurrentIdentityAssociation.class); + if (identityAssociations.isResolvable()) { + return identityAssociations.get(); + } + return null; + } } diff --git a/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLSubscriptionHandler.java b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLSubscriptionHandler.java new file mode 100644 index 0000000000000..90d3fe7d45850 --- /dev/null +++ b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLSubscriptionHandler.java @@ -0,0 +1,184 @@ +package io.quarkus.smallrye.graphql.runtime; + +import java.util.concurrent.atomic.AtomicReference; + +import javax.json.JsonObject; + +import org.jboss.logging.Logger; +import org.reactivestreams.Publisher; +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; + +import graphql.ExecutionResult; +import graphql.ExecutionResultImpl; +import graphql.GraphqlErrorBuilder; +import io.quarkus.security.identity.CurrentIdentityAssociation; +import io.quarkus.vertx.http.runtime.CurrentVertxRequest; +import io.smallrye.graphql.bootstrap.Config; +import io.smallrye.graphql.execution.ExecutionResponse; +import io.smallrye.graphql.execution.error.ExecutionErrorsService; +import io.smallrye.mutiny.Multi; +import io.smallrye.mutiny.helpers.Subscriptions; +import io.vertx.core.AsyncResult; +import io.vertx.core.Handler; +import io.vertx.core.http.HttpHeaders; +import io.vertx.core.http.ServerWebSocket; +import io.vertx.ext.web.RoutingContext; + +/** + * Handler that does the execution of GraphQL Requests + */ +public class SmallRyeGraphQLSubscriptionHandler extends SmallRyeGraphQLAbstractHandler { + private static final Logger log = Logger.getLogger(SmallRyeGraphQLSubscriptionHandler.class); + private final ExecutionErrorsService executionErrorsService; + private final Config config; + private final AtomicReference subscriptionRef = new AtomicReference<>(); + + public SmallRyeGraphQLSubscriptionHandler(Config config, CurrentIdentityAssociation currentIdentityAssociation, + CurrentVertxRequest currentVertxRequest) { + super(currentIdentityAssociation, currentVertxRequest); + this.config = config; + this.executionErrorsService = new ExecutionErrorsService(config); + } + + @Override + protected void doHandle(final RoutingContext ctx) { + if (ctx.request().headers().contains(HttpHeaders.UPGRADE, HttpHeaders.WEBSOCKET, true) && !ctx.request().isEnded()) { + ctx.request().toWebSocket(new SmallRyeWebSocketHandler()); + } else { + ctx.next(); + } + } + + private class SmallRyeWebSocketHandler implements Handler> { + + @Override + public void handle(AsyncResult event) { + if (event.succeeded()) { + ServerWebSocket serverWebSocket = event.result(); + serverWebSocket.closeHandler(new CloseHandler()); + serverWebSocket.endHandler(new EndHandler()); + serverWebSocket.exceptionHandler(new ExceptionHandler()); + serverWebSocket.textMessageHandler(new TextMessageHandler(serverWebSocket)); + } + } + } + + private class CloseHandler implements Handler { + @Override + public void handle(Void e) { + unsubscribe(); + } + } + + private class EndHandler implements Handler { + @Override + public void handle(Void e) { + unsubscribe(); + } + } + + private class ExceptionHandler implements Handler { + @Override + public void handle(Throwable e) { + log.error(e.getMessage()); + unsubscribe(); + } + } + + public void unsubscribe() { + if (subscriptionRef.get() != null) { + Subscriptions.cancel(subscriptionRef); + subscriptionRef.set(null); + } + } + + private class TextMessageHandler implements Handler { + private final SmallRyeGraphQLSubscriptionSubscriber smallRyeGraphQLSubscriptionSubscriber; + + TextMessageHandler(final ServerWebSocket serverWebSocket) { + this.smallRyeGraphQLSubscriptionSubscriber = new SmallRyeGraphQLSubscriptionSubscriber(serverWebSocket); + } + + @Override + public void handle(String message) { + JsonObject jsonInput = inputToJsonObject(message); + ExecutionResponse executionResponse = getExecutionService() + .execute(jsonInput); + + ExecutionResult executionResult = executionResponse.getExecutionResult(); + if (executionResult != null) { + // If there is error on the query, we can not start a subscription + if (executionResult.getErrors() != null && !executionResult.getErrors().isEmpty()) { + smallRyeGraphQLSubscriptionSubscriber.onNext(executionResult); + smallRyeGraphQLSubscriptionSubscriber.closeWebSocket(); + } else { + Publisher stream = executionResponse.getExecutionResult() + .getData(); + + if (stream != null) { + + Multi multiStream = Multi.createFrom().publisher(stream); + + multiStream.onFailure().recoverWithItem(failure -> { + // TODO: Below must move to SmallRye, and once 1.2.1 is releaes we can remove it here + // Once in SmallRye, this will also follow the propper error rule (show/hide) and add more details. + return new ExecutionResultImpl(GraphqlErrorBuilder.newError() + .message(failure.getMessage()) + .build()); + }).subscribe(smallRyeGraphQLSubscriptionSubscriber); + } + } + } + } + } + + private class SmallRyeGraphQLSubscriptionSubscriber implements Subscriber { + private final ServerWebSocket serverWebSocket; + + public SmallRyeGraphQLSubscriptionSubscriber(ServerWebSocket serverWebSocket) { + this.serverWebSocket = serverWebSocket; + } + + @Override + public void onSubscribe(Subscription s) { + if (subscriptionRef.compareAndSet(null, s)) { + s.request(1); + } else { + s.cancel(); + } + } + + @Override + public void onNext(ExecutionResult executionResult) { + if (serverWebSocket != null && !serverWebSocket.isClosed()) { + ExecutionResponse executionResponse = new ExecutionResponse(executionResult, config); + serverWebSocket.writeTextMessage(executionResponse.getExecutionResultAsString()); + Subscription s = subscriptionRef.get(); + s.request(1); + } else { + // Connection to client is closed, but we still receive mesages + unsubscribe(); + } + } + + @Override + public void onError(Throwable thrwbl) { + log.error("Error in GraphQL Subscription Websocket", thrwbl); + unsubscribe(); + closeWebSocket(); + } + + @Override + public void onComplete() { + unsubscribe(); + closeWebSocket(); + } + + public void closeWebSocket() { + if (!serverWebSocket.isClosed()) { + serverWebSocket.close(); + } + } + } +} diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/HttpRootPathBuildItem.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/HttpRootPathBuildItem.java index 28b897640ce6d..4965f9521d251 100644 --- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/HttpRootPathBuildItem.java +++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/HttpRootPathBuildItem.java @@ -8,6 +8,7 @@ import io.quarkus.deployment.util.UriNormalizationUtil; import io.quarkus.vertx.http.deployment.devmode.NotFoundPageDisplayableEndpointBuildItem; import io.quarkus.vertx.http.deployment.devmode.console.ConfiguredPathInfo; +import io.quarkus.vertx.http.runtime.BasicRoute; import io.quarkus.vertx.http.runtime.HandlerType; import io.vertx.core.Handler; import io.vertx.ext.web.Route; @@ -94,6 +95,25 @@ public Builder routeFunction(Function routeFunction) { "This method is not supported using this builder. Use #routeFunction(String, Consumer)"); } + public Builder orderedRoute(String route, Integer order) { + route = super.absolutePath = buildItem.resolvePath(route); + + if (route.startsWith(buildItem.getRootPath())) { + // relative to http root (leading slash for vert.x route) + this.path = "/" + UriNormalizationUtil.relativize(buildItem.getRootPath(), route); + this.routeType = RouteBuildItem.RouteType.APPLICATION_ROUTE; + } else if (route.startsWith("/")) { + // absolute path + this.path = route; + this.routeType = RouteBuildItem.RouteType.ABSOLUTE_ROUTE; + } + + BasicRoute basicRoute = new BasicRoute(this.path, -1); + + super.routeFunction = basicRoute; + return this; + } + public Builder routeFunction(String route, Consumer routeFunction) { route = super.absolutePath = buildItem.resolvePath(route); From 9367d642bad2bf5ec40aa3b9513c96a7dcac0749 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 May 2021 20:11:32 +0000 Subject: [PATCH 0111/2077] Bump junit-jupiter from 5.7.1 to 5.7.2 in /integration-tests/gradle Bumps [junit-jupiter](https://github.com/junit-team/junit5) from 5.7.1 to 5.7.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.7.1...r5.7.2) Signed-off-by: dependabot[bot] --- integration-tests/gradle/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/gradle/build.gradle b/integration-tests/gradle/build.gradle index bcbcede4acd00..b1102317b05aa 100644 --- a/integration-tests/gradle/build.gradle +++ b/integration-tests/gradle/build.gradle @@ -37,7 +37,7 @@ dependencies { testImplementation "io.quarkus:io.quarkus.gradle.plugin:${version}" testImplementation 'org.mockito:mockito-core:3.10.0' testImplementation 'org.assertj:assertj-core:3.19.0' - testImplementation 'org.junit.jupiter:junit-jupiter:5.7.1' + testImplementation 'org.junit.jupiter:junit-jupiter:5.7.2' testImplementation 'org.awaitility:awaitility:4.1.0' } From 057a7b403adb57937832fa4c87ee568d814e44fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 May 2021 21:11:15 +0000 Subject: [PATCH 0112/2077] Bump jgit.version from 5.11.0.202103091610-r to 5.11.1.202105131744-r Bumps `jgit.version` from 5.11.0.202103091610-r to 5.11.1.202105131744-r. Updates `org.eclipse.jgit` from 5.11.0.202103091610-r to 5.11.1.202105131744-r Updates `org.eclipse.jgit.http.server` from 5.11.0.202103091610-r to 5.11.1.202105131744-r Updates `org.eclipse.jgit.ssh.jsch` from 5.11.0.202103091610-r to 5.11.1.202105131744-r Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 5c6a2fa6ad728..8c44d84356369 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -161,7 +161,7 @@ 4.1.0 1.6.5 1.0.9 - 5.11.0.202103091610-r + 5.11.1.202105131744-r 7.9.0 1.0.9 4.3.5 From 9385f50d25cd90e2d484acca3814fb9cbddce973 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 May 2021 21:23:46 +0000 Subject: [PATCH 0113/2077] Bump awssdk.version from 2.16.63 to 2.16.64 Bumps `awssdk.version` from 2.16.63 to 2.16.64. Updates `software.amazon.awssdk:bom` from 2.16.63 to 2.16.64 - [Release notes](https://github.com/aws/aws-sdk-java-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-java-v2/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java-v2/compare/2.16.63...2.16.64) Updates `apache-client` from 2.16.63 to 2.16.64 Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 5c6a2fa6ad728..616b07f813da5 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -150,7 +150,7 @@ 3.8.0 1.3.1 2.9.0 - 2.16.63 + 2.16.64 2.38.1 1.4.2 1.4.32 From 06e9e62afc3b86a4fb649c24edf73d5f503f3086 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 17 May 2021 23:40:16 +0100 Subject: [PATCH 0114/2077] Upgrade to Hibernate ORM 5.5.0.Beta1 --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 5c6a2fa6ad728..1ca04e39c5bc2 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -93,7 +93,7 @@ 3.12.0 1.15 1.5.1 - 5.5.0.Alpha1 + 5.5.0.Beta1 1.0.0.CR4 6.2.0.Final 6.0.3.Final From e94ac2b8a2c973b81a23498b288fba4f6df7e76a Mon Sep 17 00:00:00 2001 From: Ken Finnigan Date: Mon, 17 May 2021 16:10:09 -0400 Subject: [PATCH 0115/2077] Remove deprecated code: - Legacy Redirect for non application endpoints - HttpRootPathBuildItem.adjustPath() - Legacy Redirect integration testsuite --- .../DataSourceHealthCheckExclusionTest.java | 2 +- .../bindings/http/FunqyHttpBuildStep.java | 2 +- .../events/FunqyKnativeEventsBuildStep.java | 4 +- .../export/JsonRegistryProcessor.java | 1 - .../export/PrometheusRegistryProcessor.java | 2 - .../deployment/ReactiveHttpProcessor.java | 6 +- .../ResteasyStandaloneBuildStep.java | 9 +- .../deployment/ResteasyReactiveProcessor.java | 8 +- .../deployment/SmallRyeGraphQLProcessor.java | 2 - .../deployment/SmallRyeHealthProcessor.java | 8 - .../deployment/SmallRyeMetricsProcessor.java | 2 - .../deployment/SmallRyeOpenApiProcessor.java | 1 - .../deployment/SwaggerUiProcessor.java | 2 - .../deployment/UndertowBuildStep.java | 6 +- .../deployment/VertxGraphqlProcessor.java | 4 +- .../ServingUIFromDefaultPathTest.java | 2 +- .../deployment/HttpRootPathBuildItem.java | 18 +- .../NonApplicationRootPathBuildItem.java | 22 +- .../vertx/http/deployment/RouteBuildItem.java | 101 ++------- .../http/deployment/VertxHttpProcessor.java | 4 - .../deployment/VertxWebRouterBuildItem.java | 8 - .../http/NonApplicationAndRootPathTest.java | 7 - .../vertx/http/NonApplicationEscapeTest.java | 1 - .../NonApplicationRootPathSiblingTest.java | 1 - .../http/runtime/HttpBuildTimeConfig.java | 22 -- .../web/deployment/VertxWebProcessor.java | 1 + .../WebJarLocatorStandaloneBuildStep.java | 5 +- integration-tests/legacy-redirect/pom.xml | 194 ------------------ .../quarkus/it/legacy/redirect/Farewell.java | 10 - .../quarkus/it/legacy/redirect/Greeting.java | 39 ---- .../it/legacy/redirect/GreetingResource.java | 47 ----- .../quarkus/it/legacy/redirect/Greetings.java | 24 --- .../io/quarkus/it/legacy/redirect/Hello.java | 20 -- .../it/legacy/redirect/MessageResource.java | 14 -- .../quarkus/it/legacy/redirect/Morning.java | 20 -- .../it/legacy/redirect/Salutation.java | 6 - .../quarkus/it/legacy/redirect/TimeOfDay.java | 10 - .../quarkus/it/legacy/redirect/Welcome.java | 10 - .../src/main/resources/application.properties | 3 - ...cyRedirectAppRootDuplicateFrameworkIT.java | 7 - ...RedirectAppRootDuplicateFrameworkTest.java | 97 --------- .../redirect/LegacyRedirectAppRootIT.java | 7 - .../redirect/LegacyRedirectAppRootTest.java | 109 ---------- .../LegacyRedirectExplicitTargetIT.java | 7 - .../LegacyRedirectExplicitTargetTest.java | 69 ------- .../LegacyRedirectFrameworkRootIT.java | 7 - .../LegacyRedirectFrameworkRootTest.java | 112 ---------- .../it/legacy/redirect/LegacyRedirectIT.java | 7 - .../legacy/redirect/LegacyRedirectTest.java | 81 -------- .../it/legacy/redirect/WebClientUtil.java | 123 ----------- .../io/quarkus/it/main/HealthTestCase.java | 42 ---- .../io/quarkus/it/main/SwaggerUITestCase.java | 7 - integration-tests/pom.xml | 1 - .../quarkus/it/metrics/MetricsTestCase.java | 7 - 54 files changed, 41 insertions(+), 1290 deletions(-) delete mode 100644 integration-tests/legacy-redirect/pom.xml delete mode 100644 integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Farewell.java delete mode 100644 integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Greeting.java delete mode 100644 integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/GreetingResource.java delete mode 100644 integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Greetings.java delete mode 100644 integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Hello.java delete mode 100644 integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/MessageResource.java delete mode 100644 integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Morning.java delete mode 100644 integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Salutation.java delete mode 100644 integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/TimeOfDay.java delete mode 100644 integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Welcome.java delete mode 100644 integration-tests/legacy-redirect/src/main/resources/application.properties delete mode 100644 integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectAppRootDuplicateFrameworkIT.java delete mode 100644 integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectAppRootDuplicateFrameworkTest.java delete mode 100644 integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectAppRootIT.java delete mode 100644 integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectAppRootTest.java delete mode 100644 integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectExplicitTargetIT.java delete mode 100644 integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectExplicitTargetTest.java delete mode 100644 integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectFrameworkRootIT.java delete mode 100644 integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectFrameworkRootTest.java delete mode 100644 integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectIT.java delete mode 100644 integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectTest.java delete mode 100644 integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/WebClientUtil.java diff --git a/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/DataSourceHealthCheckExclusionTest.java b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/DataSourceHealthCheckExclusionTest.java index cef5bf589c608..776207b1f191a 100644 --- a/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/DataSourceHealthCheckExclusionTest.java +++ b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/DataSourceHealthCheckExclusionTest.java @@ -18,7 +18,7 @@ public class DataSourceHealthCheckExclusionTest { @Test public void testDataSourceHealthCheckExclusion() { - RestAssured.when().get("/health/ready") + RestAssured.when().get("/q/health/ready") .then() .body("status", CoreMatchers.equalTo("UP")); } diff --git a/extensions/funqy/funqy-http/deployment/src/main/java/io/quarkus/funqy/deployment/bindings/http/FunqyHttpBuildStep.java b/extensions/funqy/funqy-http/deployment/src/main/java/io/quarkus/funqy/deployment/bindings/http/FunqyHttpBuildStep.java index 496711d1d6590..0751cbaa7672a 100644 --- a/extensions/funqy/funqy-http/deployment/src/main/java/io/quarkus/funqy/deployment/bindings/http/FunqyHttpBuildStep.java +++ b/extensions/funqy/funqy-http/deployment/src/main/java/io/quarkus/funqy/deployment/bindings/http/FunqyHttpBuildStep.java @@ -86,7 +86,7 @@ else if (!rootPath.endsWith("/")) String name = function.getFunctionName() == null ? function.getMethodName() : function.getFunctionName(); //String path = rootPath + name; String path = "/" + name; - routes.produce(new RouteBuildItem(path, handler, false)); + routes.produce(RouteBuildItem.builder().route(path).handler(handler).build()); } } } diff --git a/extensions/funqy/funqy-knative-events/deployment/src/main/java/io/quarkus/funqy/deployment/bindings/knative/events/FunqyKnativeEventsBuildStep.java b/extensions/funqy/funqy-knative-events/deployment/src/main/java/io/quarkus/funqy/deployment/bindings/knative/events/FunqyKnativeEventsBuildStep.java index 7ec8d445cb541..cbaa4ae12a25e 100644 --- a/extensions/funqy/funqy-knative-events/deployment/src/main/java/io/quarkus/funqy/deployment/bindings/knative/events/FunqyKnativeEventsBuildStep.java +++ b/extensions/funqy/funqy-knative-events/deployment/src/main/java/io/quarkus/funqy/deployment/bindings/knative/events/FunqyKnativeEventsBuildStep.java @@ -85,12 +85,12 @@ public void boot(ShutdownContextBuildItem shutdown, beanContainer.getValue(), executorBuildItem.getExecutorProxy()); - routes.produce(new RouteBuildItem("/", handler, false)); + routes.produce(RouteBuildItem.builder().route("/").handler(handler).build()); for (FunctionBuildItem function : functions) { String name = function.getFunctionName() == null ? function.getMethodName() : function.getFunctionName(); String path = "/" + name; - routes.produce(new RouteBuildItem(path, handler, false)); + routes.produce(RouteBuildItem.builder().route(path).handler(handler).build()); } } } diff --git a/extensions/micrometer/deployment/src/main/java/io/quarkus/micrometer/deployment/export/JsonRegistryProcessor.java b/extensions/micrometer/deployment/src/main/java/io/quarkus/micrometer/deployment/export/JsonRegistryProcessor.java index 9f4da05b43992..6b0ce9ad374f9 100644 --- a/extensions/micrometer/deployment/src/main/java/io/quarkus/micrometer/deployment/export/JsonRegistryProcessor.java +++ b/extensions/micrometer/deployment/src/main/java/io/quarkus/micrometer/deployment/export/JsonRegistryProcessor.java @@ -45,7 +45,6 @@ public void initializeJsonRegistry(MicrometerConfig config, routes.produce(nonApplicationRootPathBuildItem.routeBuilder() .routeFunction(config.export.json.path, recorder.route()) .handler(recorder.getHandler()) - .requiresLegacyRedirect() .build()); log.debug("Initialized a JSON meter registry on path=" diff --git a/extensions/micrometer/deployment/src/main/java/io/quarkus/micrometer/deployment/export/PrometheusRegistryProcessor.java b/extensions/micrometer/deployment/src/main/java/io/quarkus/micrometer/deployment/export/PrometheusRegistryProcessor.java index 19d0bd12d5e04..4392a75272f78 100644 --- a/extensions/micrometer/deployment/src/main/java/io/quarkus/micrometer/deployment/export/PrometheusRegistryProcessor.java +++ b/extensions/micrometer/deployment/src/main/java/io/quarkus/micrometer/deployment/export/PrometheusRegistryProcessor.java @@ -64,7 +64,6 @@ void createPrometheusRoute(BuildProducer routes, routes.produce(nonApplicationRootPathBuildItem.routeBuilder() .routeFunction(pConfig.path, recorder.route()) .handler(recorder.getHandler()) - .requiresLegacyRedirect() .displayOnNotFoundPage("Metrics") .build()); @@ -72,7 +71,6 @@ void createPrometheusRoute(BuildProducer routes, routes.produce(nonApplicationRootPathBuildItem.routeBuilder() .routeFunction(pConfig.path + (pConfig.path.endsWith("/") ? "*" : "/*"), recorder.route()) .handler(recorder.getHandler()) - .requiresLegacyRedirect() .build()); } } diff --git a/extensions/reactive-messaging-http/deployment/src/main/java/io/quarkus/reactivemessaging/http/deployment/ReactiveHttpProcessor.java b/extensions/reactive-messaging-http/deployment/src/main/java/io/quarkus/reactivemessaging/http/deployment/ReactiveHttpProcessor.java index 026a6543c8a87..f0e0e746a3001 100644 --- a/extensions/reactive-messaging-http/deployment/src/main/java/io/quarkus/reactivemessaging/http/deployment/ReactiveHttpProcessor.java +++ b/extensions/reactive-messaging-http/deployment/src/main/java/io/quarkus/reactivemessaging/http/deployment/ReactiveHttpProcessor.java @@ -102,8 +102,8 @@ void registerHttpConnector(BuildProducer beanProducer, .map(HttpStreamConfig::path) .distinct() .forEach(path -> { - routeProducer.produce(new RouteBuildItem(path, bodyHandler.getHandler())); - routeProducer.produce(new RouteBuildItem(path, handler)); + routeProducer.produce(RouteBuildItem.builder().route(path).handler(bodyHandler.getHandler()).build()); + routeProducer.produce(RouteBuildItem.builder().route(path).handler(handler).build()); }); } if (!wsConfigs.isEmpty()) { @@ -112,7 +112,7 @@ void registerHttpConnector(BuildProducer beanProducer, wsConfigs.stream() .map(WebSocketStreamConfig::path) .distinct() - .forEach(path -> routeProducer.produce(new RouteBuildItem(path, handler))); + .forEach(path -> routeProducer.produce(RouteBuildItem.builder().route(path).handler(handler).build())); } initSerializers(ReactiveHttpConfig.readSerializers(), generatedBeanProducer); diff --git a/extensions/resteasy-classic/resteasy/deployment/src/main/java/io/quarkus/resteasy/deployment/ResteasyStandaloneBuildStep.java b/extensions/resteasy-classic/resteasy/deployment/src/main/java/io/quarkus/resteasy/deployment/ResteasyStandaloneBuildStep.java index eb84dd521a269..3fca6ae74703f 100644 --- a/extensions/resteasy-classic/resteasy/deployment/src/main/java/io/quarkus/resteasy/deployment/ResteasyStandaloneBuildStep.java +++ b/extensions/resteasy-classic/resteasy/deployment/src/main/java/io/quarkus/resteasy/deployment/ResteasyStandaloneBuildStep.java @@ -25,7 +25,6 @@ import io.quarkus.vertx.http.deployment.DefaultRouteBuildItem; import io.quarkus.vertx.http.deployment.RequireVirtualHttpBuildItem; import io.quarkus.vertx.http.deployment.RouteBuildItem; -import io.quarkus.vertx.http.runtime.BasicRoute; import io.quarkus.vertx.http.runtime.HttpBuildTimeConfig; import io.quarkus.vertx.http.runtime.HttpConfiguration; import io.quarkus.vertx.http.runtime.VertxHttpRecorder; @@ -105,8 +104,9 @@ public void boot(ShutdownContextBuildItem shutdown, Handler handler = recorder.vertxRequestHandler(vertx.getVertx(), beanContainer.getValue(), executorBuildItem.getExecutorProxy(), httpConfiguration, resteasyVertxConfig); // Exact match for resources matched to the root path - routes.produce(new RouteBuildItem( - new BasicRoute(standalone.deploymentRootPath, VertxHttpRecorder.DEFAULT_ROUTE_ORDER + 1), handler)); + routes.produce( + RouteBuildItem.builder().orderedRoute(standalone.deploymentRootPath, VertxHttpRecorder.DEFAULT_ROUTE_ORDER + 1) + .handler(handler).build()); String matchPath = standalone.deploymentRootPath; if (matchPath.endsWith("/")) { matchPath += "*"; @@ -114,7 +114,8 @@ public void boot(ShutdownContextBuildItem shutdown, matchPath += "/*"; } // Match paths that begin with the deployment path - routes.produce(new RouteBuildItem(new BasicRoute(matchPath, VertxHttpRecorder.DEFAULT_ROUTE_ORDER + 1), handler)); + routes.produce(RouteBuildItem.builder().orderedRoute(matchPath, VertxHttpRecorder.DEFAULT_ROUTE_ORDER + 1) + .handler(handler).build()); recorder.start(shutdown, requireVirtual.isPresent()); } diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java index bcff7f240ad46..2657ba4d83311 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java @@ -123,7 +123,6 @@ import io.quarkus.security.ForbiddenException; import io.quarkus.security.UnauthorizedException; import io.quarkus.vertx.http.deployment.RouteBuildItem; -import io.quarkus.vertx.http.runtime.BasicRoute; import io.quarkus.vertx.http.runtime.HttpBuildTimeConfig; import io.quarkus.vertx.http.runtime.HttpConfiguration; import io.quarkus.vertx.http.runtime.VertxHttpRecorder; @@ -558,8 +557,8 @@ private boolean hasAnnotation(MethodInfo method, short paramPosition, DotName an Handler handler = recorder.handler(deployment); // Exact match for resources matched to the root path - routes.produce(new RouteBuildItem( - new BasicRoute(deploymentPath, VertxHttpRecorder.DEFAULT_ROUTE_ORDER + 1), handler)); + routes.produce(RouteBuildItem.builder() + .orderedRoute(deploymentPath, VertxHttpRecorder.DEFAULT_ROUTE_ORDER + 1).handler(handler).build()); String matchPath = deploymentPath; if (matchPath.endsWith("/")) { matchPath += "*"; @@ -568,7 +567,8 @@ private boolean hasAnnotation(MethodInfo method, short paramPosition, DotName an } // Match paths that begin with the deployment path routes.produce( - new RouteBuildItem(new BasicRoute(matchPath, VertxHttpRecorder.DEFAULT_ROUTE_ORDER + 1), handler)); + RouteBuildItem.builder().orderedRoute(matchPath, VertxHttpRecorder.DEFAULT_ROUTE_ORDER + 1) + .handler(handler).build()); } } } diff --git a/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java b/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java index 4ae46fae0450a..f726ba2c314da 100644 --- a/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java +++ b/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java @@ -537,13 +537,11 @@ void registerGraphQLUiHandler( .displayOnNotFoundPage("GraphQL UI") .routeConfigKey("quarkus.smallrye-graphql.ui.root-path") .handler(handler) - .requiresLegacyRedirect() .build()); routeProducer.produce(nonApplicationRootPathBuildItem.routeBuilder() .route(graphQLConfig.ui.rootPath + "*") .handler(handler) - .requiresLegacyRedirect() .build()); } diff --git a/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthProcessor.java b/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthProcessor.java index 1466a4dccc0a8..64ac387c59726 100644 --- a/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthProcessor.java +++ b/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthProcessor.java @@ -201,7 +201,6 @@ public void defineHealthRoutes(BuildProducer routes, .route(healthConfig.rootPath) .routeConfigKey("quarkus.smallrye-health.root-path") .handler(new SmallRyeHealthHandler()) - .requiresLegacyRedirect() .displayOnNotFoundPage() .blockingRoute() .build()); @@ -210,7 +209,6 @@ public void defineHealthRoutes(BuildProducer routes, routes.produce(nonApplicationRootPathBuildItem.routeBuilder() .nestedRoute(healthConfig.rootPath, healthConfig.livenessPath) .handler(new SmallRyeLivenessHandler()) - .requiresLegacyRedirect() .displayOnNotFoundPage() .blockingRoute() .build()); @@ -219,7 +217,6 @@ public void defineHealthRoutes(BuildProducer routes, routes.produce(nonApplicationRootPathBuildItem.routeBuilder() .nestedRoute(healthConfig.rootPath, healthConfig.readinessPath) .handler(new SmallRyeReadinessHandler()) - .requiresLegacyRedirect() .displayOnNotFoundPage() .blockingRoute() .build()); @@ -241,7 +238,6 @@ public void defineHealthRoutes(BuildProducer routes, routes.produce(nonApplicationRootPathBuildItem.routeBuilder() .nestedRoute(healthConfig.rootPath, healthConfig.groupPath) .handler(new SmallRyeHealthGroupHandler()) - .requiresLegacyRedirect() .displayOnNotFoundPage() .blockingRoute() .build()); @@ -251,7 +247,6 @@ public void defineHealthRoutes(BuildProducer routes, routes.produce(nonApplicationRootPathBuildItem.routeBuilder() .nestedRoute(healthConfig.rootPath, healthConfig.groupPath + "/" + healthGroup) .handler(handler) - .requiresLegacyRedirect() .displayOnNotFoundPage() .blockingRoute() .build()); @@ -261,7 +256,6 @@ public void defineHealthRoutes(BuildProducer routes, routes.produce(nonApplicationRootPathBuildItem.routeBuilder() .nestedRoute(healthConfig.rootPath, healthConfig.wellnessPath) .handler(new SmallRyeWellnessHandler()) - .requiresLegacyRedirect() .displayOnNotFoundPage() .blockingRoute() .build()); @@ -470,13 +464,11 @@ void registerHealthUiHandler( .displayOnNotFoundPage("Health UI") .routeConfigKey("quarkus.smallrye-health.ui.root-path") .handler(handler) - .requiresLegacyRedirect() .build()); routeProducer.produce(nonApplicationRootPathBuildItem.routeBuilder() .route(healthConfig.ui.rootPath + "*") .handler(handler) - .requiresLegacyRedirect() .build()); } diff --git a/extensions/smallrye-metrics/deployment/src/main/java/io/quarkus/smallrye/metrics/deployment/SmallRyeMetricsProcessor.java b/extensions/smallrye-metrics/deployment/src/main/java/io/quarkus/smallrye/metrics/deployment/SmallRyeMetricsProcessor.java index c482eaef99662..6076e4cbf8628 100644 --- a/extensions/smallrye-metrics/deployment/src/main/java/io/quarkus/smallrye/metrics/deployment/SmallRyeMetricsProcessor.java +++ b/extensions/smallrye-metrics/deployment/src/main/java/io/quarkus/smallrye/metrics/deployment/SmallRyeMetricsProcessor.java @@ -149,14 +149,12 @@ void createRoute(BuildProducer routes, routes.produce(frameworkRoot.routeBuilder() .route(metrics.path + (metrics.path.endsWith("/") ? "*" : "/*")) .handler(recorder.handler(frameworkRoot.resolvePath(metrics.path))) - .requiresLegacyRedirect() .blockingRoute() .build()); routes.produce(frameworkRoot.routeBuilder() .route(metrics.path) .handler(recorder.handler(frameworkRoot.resolvePath(metrics.path))) .displayOnNotFoundPage("Metrics") - .requiresLegacyRedirect() .blockingRoute() .build()); } diff --git a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java index 433b9b813803b..b3b46337d7f22 100644 --- a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java +++ b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java @@ -223,7 +223,6 @@ RouteBuildItem handler(LaunchModeBuildItem launch, .routeConfigKey("quarkus.smallrye-openapi.path") .handler(handler) .displayOnNotFoundPage("Open API Schema document") - .requiresLegacyRedirect() .blockingRoute() .build(); } 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 68c72055c4bf9..1954ce992edf5 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 @@ -161,13 +161,11 @@ public void registerSwaggerUiHandler(SwaggerUiRecorder recorder, .displayOnNotFoundPage("Open API UI") .routeConfigKey("quarkus.swagger-ui.path") .handler(handler) - .requiresLegacyRedirect() .build()); routes.produce(nonApplicationRootPathBuildItem.routeBuilder() .route(swaggerUiConfig.path + "*") .handler(handler) - .requiresLegacyRedirect() .build()); } } diff --git a/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/UndertowBuildStep.java b/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/UndertowBuildStep.java index 66eb197786837..ea6ad11c433e0 100644 --- a/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/UndertowBuildStep.java +++ b/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/UndertowBuildStep.java @@ -194,8 +194,10 @@ public ServiceStartBuildItem boot(UndertowDeploymentRecorder recorder, if (servletContextPathBuildItem.getServletContextPath().equals("/")) { undertowProducer.accept(new DefaultRouteBuildItem(ut)); } else { - routeProducer.produce(new RouteBuildItem(servletContextPathBuildItem.getServletContextPath() + "/*", ut, false)); - routeProducer.produce(new RouteBuildItem(servletContextPathBuildItem.getServletContextPath(), ut, false)); + routeProducer.produce(RouteBuildItem.builder().route(servletContextPathBuildItem.getServletContextPath() + "/*") + .handler(ut).build()); + routeProducer.produce( + RouteBuildItem.builder().route(servletContextPathBuildItem.getServletContextPath()).handler(ut).build()); } return new ServiceStartBuildItem("undertow"); } diff --git a/extensions/vertx-graphql/deployment/src/main/java/io/quarkus/vertx/graphql/deployment/VertxGraphqlProcessor.java b/extensions/vertx-graphql/deployment/src/main/java/io/quarkus/vertx/graphql/deployment/VertxGraphqlProcessor.java index b55f9b6abda17..3f19e383ca710 100644 --- a/extensions/vertx-graphql/deployment/src/main/java/io/quarkus/vertx/graphql/deployment/VertxGraphqlProcessor.java +++ b/extensions/vertx-graphql/deployment/src/main/java/io/quarkus/vertx/graphql/deployment/VertxGraphqlProcessor.java @@ -73,14 +73,12 @@ void registerVertxGraphqlUI(VertxGraphqlRecorder recorder, routes.produce(nonApplicationRootPathBuildItem.routeBuilder() .route(path) .handler(handler) - .requiresLegacyRedirect() - .displayOnNotFoundPage("GraphQL UI", path + "/") + .displayOnNotFoundPage("GraphQL UI") .build()); routes.produce( nonApplicationRootPathBuildItem.routeBuilder() .route(path + "/*") .handler(handler) - .requiresLegacyRedirect() .build()); // Body handler required in Vert.x 4, to avoid DDOS attack. body.produce(new RequireBodyHandlerBuildItem()); diff --git a/extensions/vertx-graphql/deployment/src/test/java/io/quarkus/vertx/graphql/deployment/ServingUIFromDefaultPathTest.java b/extensions/vertx-graphql/deployment/src/test/java/io/quarkus/vertx/graphql/deployment/ServingUIFromDefaultPathTest.java index 4eb9cd8110313..ea97b7ab1c862 100644 --- a/extensions/vertx-graphql/deployment/src/test/java/io/quarkus/vertx/graphql/deployment/ServingUIFromDefaultPathTest.java +++ b/extensions/vertx-graphql/deployment/src/test/java/io/quarkus/vertx/graphql/deployment/ServingUIFromDefaultPathTest.java @@ -16,6 +16,6 @@ public class ServingUIFromDefaultPathTest { @Test public void shouldServeVertxGraphqlUiFromDefaultPath() { - RestAssured.when().get("/graphql-ui").then().statusCode(200); + RestAssured.when().get("/q/graphql-ui").then().statusCode(200); } } diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/HttpRootPathBuildItem.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/HttpRootPathBuildItem.java index 28b897640ce6d..fd1d51d6c1d52 100644 --- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/HttpRootPathBuildItem.java +++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/HttpRootPathBuildItem.java @@ -39,16 +39,6 @@ public String getRootPath() { return rootPath.getPath(); } - /** - * Adjusts the path in relation to `quarkus.http.root-path`. - * Any leading slash will be removed to resolve relatively. - * - * @deprecated Use {@code resolvePath} instead. Do not use this method. Will be removed in Quarkus 2.0 - */ - public String adjustPath(String path) { - return resolvePath(path.startsWith("/") ? path.substring(1) : path); - } - /** * Resolve path into an absolute path. * If path is relative, it will be resolved against `quarkus.http.root-path`. @@ -164,12 +154,6 @@ public Builder displayOnNotFoundPage(String notFoundPageTitle) { return this; } - @Override - public Builder displayOnNotFoundPage(String notFoundPageTitle, String notFoundPagePath) { - super.displayOnNotFoundPage(notFoundPageTitle, notFoundPagePath); - return this; - } - @Override public Builder routeConfigKey(String attributeName) { super.routeConfigKey(attributeName); @@ -178,7 +162,7 @@ public Builder routeConfigKey(String attributeName) { @Override public RouteBuildItem build() { - return new RouteBuildItem(this, routeType, false); + return new RouteBuildItem(this, routeType); } @Override diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/NonApplicationRootPathBuildItem.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/NonApplicationRootPathBuildItem.java index e16242c878c30..16a1b4cbfa4e6 100644 --- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/NonApplicationRootPathBuildItem.java +++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/NonApplicationRootPathBuildItem.java @@ -179,7 +179,6 @@ public Builder routeBuilder() { */ public static class Builder extends RouteBuildItem.Builder { private final NonApplicationRootPathBuildItem buildItem; - private boolean requiresLegacyRedirect = false; private RouteBuildItem.RouteType routeType = RouteBuildItem.RouteType.FRAMEWORK_ROUTE; private String path; @@ -234,15 +233,6 @@ public Builder nestedRoute(String baseRoute, String subRoute) { return this; } - /** - * @deprecated This will be removed in Quarkus 2.0, don't use unless you have to. - */ - @Deprecated - public Builder requiresLegacyRedirect() { - this.requiresLegacyRedirect = true; - return this; - } - @Override public Builder handler(Handler handler) { super.handler(handler); @@ -279,12 +269,6 @@ public Builder displayOnNotFoundPage(String notFoundPageTitle) { return this; } - @Override - public Builder displayOnNotFoundPage(String notFoundPageTitle, String notFoundPagePath) { - super.displayOnNotFoundPage(notFoundPageTitle, notFoundPagePath); - return this; - } - @Override public Builder routeConfigKey(String attributeName) { super.routeConfigKey(attributeName); @@ -293,11 +277,7 @@ public Builder routeConfigKey(String attributeName) { @Override public RouteBuildItem build() { - // If path is same as absolute, we don't enable legacy redirect - if (requiresLegacyRedirect && path.equals(super.absolutePath)) { - requiresLegacyRedirect = false; - } - return new RouteBuildItem(this, routeType, requiresLegacyRedirect); + return new RouteBuildItem(this, routeType); } @Override diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/RouteBuildItem.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/RouteBuildItem.java index f3bf8101515bb..81262e95feb02 100644 --- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/RouteBuildItem.java +++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/RouteBuildItem.java @@ -23,70 +23,14 @@ public static Builder builder() { private final Handler handler; private final HandlerType type; private final RouteType routeType; - private final boolean requiresLegacyRedirect; private final NotFoundPageDisplayableEndpointBuildItem notFoundPageDisplayableEndpoint; private final ConfiguredPathInfo devConsoleResolvedPathBuildItem; - /** - * @deprecated Use the Builder instead. - */ - @Deprecated - public RouteBuildItem(Function routeFunction, Handler handler, HandlerType type) { - this.routeFunction = routeFunction; - this.handler = handler; - this.type = type; - this.routeType = RouteType.APPLICATION_ROUTE; - this.requiresLegacyRedirect = false; - this.notFoundPageDisplayableEndpoint = null; - this.devConsoleResolvedPathBuildItem = null; - } - - /** - * @deprecated Use the Builder instead. - */ - @Deprecated - public RouteBuildItem(Function routeFunction, Handler handler) { - this(routeFunction, handler, HandlerType.NORMAL); - } - - /** - * @deprecated Use the Builder instead. - */ - @Deprecated - public RouteBuildItem(String route, Handler handler, HandlerType type, boolean resume) { - this(new BasicRoute(route), handler, type); - } - - /** - * @deprecated Use the Builder instead. - */ - @Deprecated - public RouteBuildItem(String route, Handler handler, HandlerType type) { - this(new BasicRoute(route), handler, type); - } - - /** - * @deprecated Use the Builder instead. - */ - @Deprecated - public RouteBuildItem(String route, Handler handler, boolean resume) { - this(new BasicRoute(route), handler, HandlerType.NORMAL); - } - - /** - * @deprecated Use the Builder instead. - */ - @Deprecated - public RouteBuildItem(String route, Handler handler) { - this(new BasicRoute(route), handler); - } - - RouteBuildItem(Builder builder, RouteType routeType, boolean requiresLegacyRedirect) { + RouteBuildItem(Builder builder, RouteType routeType) { this.routeFunction = builder.routeFunction; this.handler = builder.handler; this.type = builder.type; this.routeType = routeType; - this.requiresLegacyRedirect = requiresLegacyRedirect; this.notFoundPageDisplayableEndpoint = builder.getNotFoundEndpoint(); this.devConsoleResolvedPathBuildItem = builder.getRouteConfigInfo(); } @@ -115,10 +59,6 @@ public boolean isAbsoluteRoute() { return routeType.equals(RouteType.ABSOLUTE_ROUTE); } - public boolean isRequiresLegacyRedirect() { - return requiresLegacyRedirect; - } - public NotFoundPageDisplayableEndpointBuildItem getNotFoundPageDisplayableEndpoint() { return notFoundPageDisplayableEndpoint; } @@ -148,18 +88,6 @@ public static class Builder { protected String routeConfigKey; protected String absolutePath; - /** - * Use HttpRootPathBuildItem and NonApplicationRootPathBuildItem to - * ensure paths are constructed/normalized correctly - * - * @deprecated - * @see HttpRootPathBuildItem#routeBuilder() - * @see NonApplicationRootPathBuildItem#routeBuilder() - */ - @Deprecated - public Builder() { - } - /** * {@link #routeFunction(String, Consumer)} should be used instead * @@ -194,6 +122,18 @@ public Builder route(String route) { return this; } + /** + * @param route A normalized path used to define a basic route + * (e.g. use HttpRootPathBuildItem to construct/resolve the path value). This path this is also + * used on the "Not Found" page in dev mode. + * @param order Priority ordering of the route + */ + public Builder orderedRoute(String route, Integer order) { + this.routeFunction = new BasicRoute(route, order); + this.notFoundPagePath = this.routePath = route; + return this; + } + public Builder handler(Handler handler) { this.handler = handler; return this; @@ -225,26 +165,13 @@ public Builder displayOnNotFoundPage(String notFoundPageTitle) { return this; } - /** - * @deprecated Specify the path as part of defining the route - * @see #route(String) - * @see #routeFunction(String, Consumer) - */ - @Deprecated - public Builder displayOnNotFoundPage(String notFoundPageTitle, String notFoundPagePath) { - this.displayOnNotFoundPage = true; - this.notFoundPageTitle = notFoundPageTitle; - this.notFoundPagePath = notFoundPagePath; - return this; - } - public Builder routeConfigKey(String attributeName) { this.routeConfigKey = attributeName; return this; } public RouteBuildItem build() { - return new RouteBuildItem(this, RouteType.APPLICATION_ROUTE, false); + return new RouteBuildItem(this, RouteType.APPLICATION_ROUTE); } protected ConfiguredPathInfo getRouteConfigInfo() { diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java index 6a8f341e1808a..22f5ce0fdc7d2 100644 --- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java +++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java @@ -156,10 +156,6 @@ VertxWebRouterBuildItem initializeRouter(VertxHttpRecorder recorder, } recorder.addRoute(frameworkRouter, route.getRouteFunction(), route.getHandler(), route.getType()); - - if (httpBuildTimeConfig.redirectToNonApplicationRootPath && route.isRequiresLegacyRedirect()) { - redirectRoutes.add(route); - } } else if (route.isAbsoluteRoute()) { // Add Route to "/" if (!mainRouterCreated) { diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxWebRouterBuildItem.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxWebRouterBuildItem.java index dea1d1cec4060..b3c9a7a064564 100644 --- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxWebRouterBuildItem.java +++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxWebRouterBuildItem.java @@ -17,14 +17,6 @@ public final class VertxWebRouterBuildItem extends SimpleBuildItem { this.frameworkRouter = frameworkRouter; } - /** - * @deprected Use {@link #getHttpRouter()} - */ - @Deprecated - public RuntimeValue getRouter() { - return getHttpRouter(); - } - public RuntimeValue getHttpRouter() { return httpRouter; } diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/NonApplicationAndRootPathTest.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/NonApplicationAndRootPathTest.java index b73a2bf0d103c..0c1837c745803 100644 --- a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/NonApplicationAndRootPathTest.java +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/NonApplicationAndRootPathTest.java @@ -45,7 +45,6 @@ public void execute(BuildContext context) { .route("non-app-relative") .handler(new MyHandler()) .blockingRoute() - .requiresLegacyRedirect() .build()); } }).produces(RouteBuildItem.class) @@ -64,12 +63,6 @@ public void handle(RoutingContext routingContext) { } } - @Test - public void testNonApplicationEndpointOnRootPathWithRedirect() { - // Note RestAssured knows the path prefix is /api - RestAssured.given().get("/non-app-relative").then().statusCode(200).body(Matchers.equalTo("/api/q/non-app-relative")); - } - @Test public void testNonApplicationEndpointDirect() { // Note RestAssured knows the path prefix is /api diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/NonApplicationEscapeTest.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/NonApplicationEscapeTest.java index 2873c533f58b1..a880025236e0d 100644 --- a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/NonApplicationEscapeTest.java +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/NonApplicationEscapeTest.java @@ -56,7 +56,6 @@ public void execute(BuildContext context) { .route("/non-app-absolute") .handler(new MyHandler()) .blockingRoute() - .requiresLegacyRedirect() .build()); } }).produces(RouteBuildItem.class) diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/NonApplicationRootPathSiblingTest.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/NonApplicationRootPathSiblingTest.java index 3cbd535370d15..77b3ba2192792 100644 --- a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/NonApplicationRootPathSiblingTest.java +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/NonApplicationRootPathSiblingTest.java @@ -46,7 +46,6 @@ public void execute(BuildContext context) { .route("non-app-relative") .handler(new MyHandler()) .blockingRoute() - .requiresLegacyRedirect() .build()); } }).produces(RouteBuildItem.class) diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/HttpBuildTimeConfig.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/HttpBuildTimeConfig.java index 6bca11e7fe1f1..a0a8383110a2a 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/HttpBuildTimeConfig.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/HttpBuildTimeConfig.java @@ -49,28 +49,6 @@ public class HttpBuildTimeConfig { @ConfigItem(defaultValue = "q") public String nonApplicationRootPath; - /** - * Provide redirect endpoints for extension-provided endpoints existing prior to Quarkus 1.11. - * This will trigger HTTP 301 Redirects for the following: - * - * * `/graphql-ui` - * * `/health` - * * `/health-ui` - * * `/metrics` - * * `/openapi` - * * `/swagger-ui` - * - * Default is `true` for Quarkus 1.11.x to facilitate transition to name-spaced URIs using - * `${quarkus.http.non-application-root-path}`. - * - * Quarkus 1.13 will change the default to `false`, - * and the config item will be removed in Quarkus 2.0. - * - * @asciidoclet - */ - @ConfigItem(defaultValue = "true") - public boolean redirectToNonApplicationRootPath; - /** * The REST Assured client timeout for testing. */ diff --git a/extensions/vertx-web/deployment/src/main/java/io/quarkus/vertx/web/deployment/VertxWebProcessor.java b/extensions/vertx-web/deployment/src/main/java/io/quarkus/vertx/web/deployment/VertxWebProcessor.java index b35b965f0e0c8..ff8ec96ac6349 100644 --- a/extensions/vertx-web/deployment/src/main/java/io/quarkus/vertx/web/deployment/VertxWebProcessor.java +++ b/extensions/vertx-web/deployment/src/main/java/io/quarkus/vertx/web/deployment/VertxWebProcessor.java @@ -390,6 +390,7 @@ public boolean test(String name) { Function routeFunction = recorder.createRouteFunction(matcher, bodyHandler.getHandler()); + //TODO This needs to be refactored to use routeFunction() taking a Consumer instead RouteBuildItem.Builder builder = RouteBuildItem.builder() .routeFunction(routeFunction) .handlerType(handlerType) diff --git a/extensions/webjars-locator/deployment/src/main/java/io/quarkus/webjar/locator/deployment/WebJarLocatorStandaloneBuildStep.java b/extensions/webjars-locator/deployment/src/main/java/io/quarkus/webjar/locator/deployment/WebJarLocatorStandaloneBuildStep.java index ebff8aecd2a9f..d0cd4792ef50b 100644 --- a/extensions/webjars-locator/deployment/src/main/java/io/quarkus/webjar/locator/deployment/WebJarLocatorStandaloneBuildStep.java +++ b/extensions/webjars-locator/deployment/src/main/java/io/quarkus/webjar/locator/deployment/WebJarLocatorStandaloneBuildStep.java @@ -35,9 +35,8 @@ public void findWebjarsAndCreateHandler( String webjarRootPath = (rootPath.endsWith("/")) ? rootPath + "webjars/" : rootPath + "/webjars/"; feature.produce(new FeatureBuildItem(Feature.WEBJARS_LOCATOR)); routes.produce( - new RouteBuildItem(webjarRootPath + "*", - recorder.getHandler(webjarRootPath, webjarNameToVersionMap), - false)); + RouteBuildItem.builder().route(webjarRootPath + "*") + .handler(recorder.getHandler(webjarRootPath, webjarNameToVersionMap)).build()); } else { log.warn("No WebJars were found in the project. Requests to the /webjars/ path will always return 404 (Not Found)"); } diff --git a/integration-tests/legacy-redirect/pom.xml b/integration-tests/legacy-redirect/pom.xml deleted file mode 100644 index c38d191a4bb96..0000000000000 --- a/integration-tests/legacy-redirect/pom.xml +++ /dev/null @@ -1,194 +0,0 @@ - - - 4.0.0 - - - io.quarkus - quarkus-integration-tests-parent - 999-SNAPSHOT - - - quarkus-integration-test-legacy-redirect - Quarkus - Integration Tests - Legacy redirect - - - - io.quarkus - quarkus-smallrye-graphql - - - io.quarkus - quarkus-smallrye-health - - - io.quarkus - quarkus-smallrye-metrics - - - io.quarkus - quarkus-smallrye-openapi - - - io.quarkus - quarkus-swagger-ui - - - - - io.quarkus - quarkus-resteasy - - - io.quarkus - quarkus-vertx-http - - - - - io.quarkus - quarkus-kubernetes - - - - - io.quarkus - quarkus-junit5 - test - - - io.vertx - vertx-web-client - test - - - org.jboss.logging - commons-logging-jboss-logging - test - - - - - io.quarkus - quarkus-smallrye-graphql-deployment - ${project.version} - pom - test - - - * - * - - - - - io.quarkus - quarkus-smallrye-health-deployment - ${project.version} - pom - test - - - * - * - - - - - io.quarkus - quarkus-smallrye-metrics-deployment - ${project.version} - pom - test - - - * - * - - - - - io.quarkus - quarkus-smallrye-openapi-deployment - ${project.version} - pom - test - - - * - * - - - - - io.quarkus - quarkus-swagger-ui-deployment - ${project.version} - pom - test - - - * - * - - - - - io.quarkus - quarkus-kubernetes-deployment - ${project.version} - pom - test - - - * - * - - - - - io.quarkus - quarkus-resteasy-deployment - ${project.version} - pom - test - - - * - * - - - - - io.quarkus - quarkus-vertx-http-deployment - ${project.version} - pom - test - - - * - * - - - - - - - - - io.quarkus - quarkus-maven-plugin - - - - build - - - - - - - - diff --git a/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Farewell.java b/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Farewell.java deleted file mode 100644 index 215a3bbdefc07..0000000000000 --- a/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Farewell.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.quarkus.it.legacy.redirect; - -public class Farewell extends Salutation { - - @Override - public String getType() { - return "Farewell"; - } - -} diff --git a/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Greeting.java b/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Greeting.java deleted file mode 100644 index fb8d9f95f9355..0000000000000 --- a/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Greeting.java +++ /dev/null @@ -1,39 +0,0 @@ -package io.quarkus.it.legacy.redirect; - -import java.time.LocalTime; - -public class Greeting extends Salutation { - - private String message; - private LocalTime time; - - public Greeting() { - } - - public Greeting(String message, LocalTime time) { - this.message = message; - this.time = time; - } - - public String getMessage() { - return message; - } - - public LocalTime getTime() { - return time; - } - - public void setMessage(String message) { - this.message = message; - } - - public void setTime(LocalTime time) { - this.time = time; - } - - @Override - public String getType() { - return "Greet"; - } - -} diff --git a/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/GreetingResource.java b/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/GreetingResource.java deleted file mode 100644 index dc834e4207880..0000000000000 --- a/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/GreetingResource.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.quarkus.it.legacy.redirect; - -import java.time.LocalTime; -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.microprofile.config.inject.ConfigProperty; -import org.eclipse.microprofile.graphql.GraphQLApi; -import org.eclipse.microprofile.graphql.Mutation; -import org.eclipse.microprofile.graphql.Name; -import org.eclipse.microprofile.graphql.Query; -import org.eclipse.microprofile.graphql.Source; - -@GraphQLApi -public class GreetingResource { - - @ConfigProperty(name = "message") - String message; - - @Query - public String message() { - return message; - } - - @Query - public Greeting hello() { - return new Greeting("hello", LocalTime.of(11, 34)); - } - - @Mutation - public Greetings load(Greetings greetings) { - return greetings; - } - - @Name("options") - public List buildInOptions(@Source Greeting greeting) { - List options = new ArrayList<>(); - options.add(new Hello()); - options.add(new Morning()); - return options; - } - - @Query - public Farewell farewell() { - return new Farewell(); - } -} diff --git a/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Greetings.java b/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Greetings.java deleted file mode 100644 index 3c8841ff3c0d4..0000000000000 --- a/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Greetings.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.quarkus.it.legacy.redirect; - -import java.util.List; - -public class Greetings { - private String language; - private List hellos; - - public String getLanguage() { - return language; - } - - public void setLanguage(String language) { - this.language = language; - } - - public List getHellos() { - return hellos; - } - - public void setHellos(List hellos) { - this.hellos = hellos; - } -} diff --git a/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Hello.java b/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Hello.java deleted file mode 100644 index 0e1586a5a18a3..0000000000000 --- a/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Hello.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.quarkus.it.legacy.redirect; - -import java.time.LocalTime; - -public class Hello extends Greeting { - - private TimeOfDay timeOfDay = TimeOfDay.ANY; - - public Hello() { - super("Hello", LocalTime.now()); - } - - public TimeOfDay getTimeOfDay() { - return timeOfDay; - } - - public void setTimeOfDay(TimeOfDay timeOfDay) { - this.timeOfDay = timeOfDay; - } -} diff --git a/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/MessageResource.java b/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/MessageResource.java deleted file mode 100644 index 62eab08d02e7b..0000000000000 --- a/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/MessageResource.java +++ /dev/null @@ -1,14 +0,0 @@ -package io.quarkus.it.legacy.redirect; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; - -@Path("/message") -public class MessageResource { - - @GET - public String message() { - return "hello world"; - } - -} diff --git a/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Morning.java b/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Morning.java deleted file mode 100644 index 07e45d1f5e07c..0000000000000 --- a/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Morning.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.quarkus.it.legacy.redirect; - -import java.time.LocalTime; - -public class Morning extends Greeting { - - private TimeOfDay timeOfDay = TimeOfDay.MORNING; - - public Morning() { - super("Good Morning", LocalTime.now()); - } - - public TimeOfDay getTimeOfDay() { - return timeOfDay; - } - - public void setTimeOfDay(TimeOfDay timeOfDay) { - this.timeOfDay = timeOfDay; - } -} diff --git a/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Salutation.java b/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Salutation.java deleted file mode 100644 index 2f6d65e8b4602..0000000000000 --- a/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Salutation.java +++ /dev/null @@ -1,6 +0,0 @@ -package io.quarkus.it.legacy.redirect; - -public abstract class Salutation { - - public abstract String getType(); -} diff --git a/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/TimeOfDay.java b/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/TimeOfDay.java deleted file mode 100644 index b8eff96f3cf86..0000000000000 --- a/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/TimeOfDay.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.quarkus.it.legacy.redirect; - -public enum TimeOfDay { - - ANY, - MORNING, - AFTERNOON, - EVENING, - NIGHT -} diff --git a/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Welcome.java b/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Welcome.java deleted file mode 100644 index 044412e210726..0000000000000 --- a/integration-tests/legacy-redirect/src/main/java/io/quarkus/it/legacy/redirect/Welcome.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.quarkus.it.legacy.redirect; - -public class Welcome extends Salutation { - - @Override - public String getType() { - return "Welcome"; - } - -} diff --git a/integration-tests/legacy-redirect/src/main/resources/application.properties b/integration-tests/legacy-redirect/src/main/resources/application.properties deleted file mode 100644 index d1b9662258193..0000000000000 --- a/integration-tests/legacy-redirect/src/main/resources/application.properties +++ /dev/null @@ -1,3 +0,0 @@ -quarkus.http.redirect-to-non-application-root-path=true -message=Production -mp.health.default.readiness.empty.response=UP diff --git a/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectAppRootDuplicateFrameworkIT.java b/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectAppRootDuplicateFrameworkIT.java deleted file mode 100644 index 9271a7e5b16de..0000000000000 --- a/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectAppRootDuplicateFrameworkIT.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.quarkus.it.legacy.redirect; - -import io.quarkus.test.junit.NativeImageTest; - -@NativeImageTest -class LegacyRedirectAppRootDuplicateFrameworkIT extends LegacyRedirectAppRootTest { -} diff --git a/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectAppRootDuplicateFrameworkTest.java b/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectAppRootDuplicateFrameworkTest.java deleted file mode 100644 index 8135c5c87af52..0000000000000 --- a/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectAppRootDuplicateFrameworkTest.java +++ /dev/null @@ -1,97 +0,0 @@ -package io.quarkus.it.legacy.redirect; - -import java.net.URL; -import java.util.HashMap; -import java.util.Map; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import io.quarkus.test.common.http.TestHTTPResource; -import io.quarkus.test.junit.QuarkusTest; -import io.quarkus.test.junit.QuarkusTestProfile; -import io.quarkus.test.junit.TestProfile; - -@QuarkusTest -@TestProfile(LegacyRedirectAppRootDuplicateFrameworkTest.SetApplicationSameFrameworkRoot.class) -class LegacyRedirectAppRootDuplicateFrameworkTest { - - // When the root path and the framework path are the same, there are - // no redirects at all. - - public static class SetApplicationSameFrameworkRoot implements QuarkusTestProfile { - @Override - public Map getConfigOverrides() { - Map overrides = new HashMap<>(); - overrides.put("quarkus.http.root-path", "/app"); - overrides.put("quarkus.http.non-application-root-path", "/app"); - return overrides; - } - } - - @TestHTTPResource(value = "/") - URL hostPortUrl; - - WebClientUtil clientUtil = new WebClientUtil(); - - @BeforeEach - void setUrl() { - clientUtil.setHostPortUrl(hostPortUrl); - } - - @Test - public void testGraphQlUnchangedNeverRedirect() { - // Not found: moved with application endpoint - clientUtil.validate("/graphql", 404); - // Not the same as 404.. graphql is found in the right place - clientUtil.validate("/app/graphql", 405); - } - - @Test - public void testGraphQlUiWithRedirect() { - // Not found: moved with application endpoint - clientUtil.validate("/graphql-ui", 404); - - clientUtil.validate("/app/graphql-ui", 302); - } - - @Test - // TODO - MP4 - Require SR Health 3.0.1 - @Disabled - public void testHealthWithRedirect() { - // Not found: moved with application endpoint - clientUtil.validate("/health", 404); - - clientUtil.validate("/app/health", 200); - clientUtil.validate("/app/health/group", 200); - clientUtil.validate("/app/health/live", 200); - clientUtil.validate("/app/health/ready", 200); - clientUtil.validate("/app/health/well", 200); - clientUtil.validate("/app/health-ui", 302); - } - - @Test - public void testMetricsWithRedirect() { - // Not found: moved with application endpoint - clientUtil.validate("/metrics", 404); - - clientUtil.validateText("/app/metrics", 200); - } - - @Test - public void testOpenApiWithRedirect() { - // Not found: moved with application endpoint - clientUtil.validate("/openapi", 404); - - clientUtil.validate("/app/openapi", 200); - } - - @Test - public void testSwaggerUiWithRedirect() { - // Not found: moved with application endpoint - clientUtil.validate("/swagger-ui", 404); - - clientUtil.validate("/app/swagger-ui", 302); - } -} diff --git a/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectAppRootIT.java b/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectAppRootIT.java deleted file mode 100644 index b3c3d70ff0486..0000000000000 --- a/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectAppRootIT.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.quarkus.it.legacy.redirect; - -import io.quarkus.test.junit.NativeImageTest; - -@NativeImageTest -class LegacyRedirectAppRootIT extends LegacyRedirectAppRootTest { -} diff --git a/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectAppRootTest.java b/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectAppRootTest.java deleted file mode 100644 index dbb36a21f6584..0000000000000 --- a/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectAppRootTest.java +++ /dev/null @@ -1,109 +0,0 @@ -package io.quarkus.it.legacy.redirect; - -import java.net.URL; -import java.util.Collections; -import java.util.Map; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import io.quarkus.test.common.http.TestHTTPResource; -import io.quarkus.test.junit.QuarkusTest; -import io.quarkus.test.junit.QuarkusTestProfile; -import io.quarkus.test.junit.TestProfile; - -@QuarkusTest -@TestProfile(LegacyRedirectAppRootTest.SetApplicationRoot.class) -class LegacyRedirectAppRootTest { - - // Legacy redirect behavior is implicitly scoped to the configured - // http root (i.e. /app/health will be redirected) - - public static class SetApplicationRoot implements QuarkusTestProfile { - @Override - public Map getConfigOverrides() { - return Collections.singletonMap("quarkus.http.root-path", "/app"); - } - } - - @TestHTTPResource(value = "/") - URL hostPortUrl; - - WebClientUtil clientUtil = new WebClientUtil(); - - @BeforeEach - void setUrl() { - clientUtil.setHostPortUrl(hostPortUrl); - } - - @Test - public void testGraphQlUnchangedNeverRedirect() { - // Not found: moved with application endpoint - clientUtil.validate("/graphql", 404); - // Not the same as 404.. graphql is found in the right place - clientUtil.validate("/app/graphql", 405); - } - - @Test - public void testGraphQlUiWithRedirect() { - // Not found: moved with application endpoint - clientUtil.validate("/graphql-ui", 404); - - clientUtil.validate("/app/graphql-ui", 301, "/app/q/graphql-ui"); - clientUtil.validate("/app/q/graphql-ui", 302); - } - - @Test - // TODO - MP4 - Require SR Health 3.0.1 - @Disabled - public void testHealthWithRedirect() { - // Not found: moved with application endpoint - clientUtil.validate("/health", 404); - - clientUtil.validate("/app/health", 301, "/app/q/health"); - clientUtil.validate("/app/q/health", 200); - - clientUtil.validate("/app/health/group", 301, "/app/q/health/group"); - clientUtil.validate("/app/q/health/group", 200); - - clientUtil.validate("/app/health/live", 301, "/app/q/health/live"); - clientUtil.validate("/app/q/health/live", 200); - - clientUtil.validate("/app/health/ready", 301, "/app/q/health/ready"); - clientUtil.validate("/app/q/health/ready", 200); - - clientUtil.validate("/app/health/well", 301, "/app/q/health/well"); - clientUtil.validate("/app/q/health/well", 200); - - clientUtil.validate("/app/health-ui", 301, "/app/q/health-ui"); - clientUtil.validate("/app/q/health-ui", 302); - } - - @Test - public void testMetricsWithRedirect() { - // Not found: moved with application endpoint - clientUtil.validate("/metrics", 404); - - clientUtil.validate("/app/metrics", 301, "/app/q/metrics"); - clientUtil.validateText("/app/q/metrics", 200); - } - - @Test - public void testOpenApiWithRedirect() { - // Not found: moved with application endpoint - clientUtil.validate("/openapi", 404); - - clientUtil.validate("/app/openapi", 301, "/app/q/openapi"); - clientUtil.validate("/app/q/openapi", 200); - } - - @Test - public void testSwaggerUiWithRedirect() { - // Not found: moved with application endpoint - clientUtil.validate("/swagger-ui", 404); - - clientUtil.validate("/app/swagger-ui", 301, "/app/q/swagger-ui"); - clientUtil.validate("/app/q/swagger-ui", 302); - } -} diff --git a/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectExplicitTargetIT.java b/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectExplicitTargetIT.java deleted file mode 100644 index d748459ffc07a..0000000000000 --- a/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectExplicitTargetIT.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.quarkus.it.legacy.redirect; - -import io.quarkus.test.junit.NativeImageTest; - -@NativeImageTest -class LegacyRedirectExplicitTargetIT extends LegacyRedirectAppRootTest { -} diff --git a/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectExplicitTargetTest.java b/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectExplicitTargetTest.java deleted file mode 100644 index 90744532fa25a..0000000000000 --- a/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectExplicitTargetTest.java +++ /dev/null @@ -1,69 +0,0 @@ -package io.quarkus.it.legacy.redirect; - -import java.net.URL; -import java.util.HashMap; -import java.util.Map; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import io.quarkus.test.common.http.TestHTTPResource; -import io.quarkus.test.junit.QuarkusTest; -import io.quarkus.test.junit.QuarkusTestProfile; -import io.quarkus.test.junit.TestProfile; - -@QuarkusTest -@TestProfile(LegacyRedirectExplicitTargetTest.SetExplicitTarget.class) -class LegacyRedirectExplicitTargetTest { - - // When explicit endpoints are specified, those endpoints should be used - // directly, which should disable the compatibility redirect for that - // endpoint (404) - - public static class SetExplicitTarget implements QuarkusTestProfile { - @Override - public Map getConfigOverrides() { - Map overrides = new HashMap<>(); - overrides.put("quarkus.http.root-path", "/app"); - overrides.put("quarkus.http.non-application-root-path", "/framework"); - overrides.put("quarkus.smallrye-metrics.path", "/my-metrics"); - overrides.put("quarkus.smallrye-health.liveness-path", "/liveness"); - return overrides; - } - } - - @TestHTTPResource(value = "/") - URL hostPortUrl; - - WebClientUtil clientUtil = new WebClientUtil(); - - @BeforeEach - void setUrl() { - clientUtil.setHostPortUrl(hostPortUrl); - } - - @Test - public void testHealthWithRedirect() { - // Not found: moved with application endpoint - clientUtil.validate("/health", 404); - - clientUtil.validate("/app/health", 301, "/framework/health"); - clientUtil.validate("/framework/health", 200); - - clientUtil.validate("/app/health/liveness", 404); - clientUtil.validate("/framework/health/liveness", 404); - clientUtil.validate("/liveness", 200); - } - - @Test - public void testMetricsWithRedirect() { - // Not found: moved with application endpoint - clientUtil.validate("/metrics", 404); - clientUtil.validate("/app/metrics", 404); - clientUtil.validate("/framework/metrics", 404); - - clientUtil.validateText("/my-metrics", 200); - clientUtil.validate("/app/my-metrics", 404); - clientUtil.validate("/framework/my-metrics", 404); - } -} diff --git a/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectFrameworkRootIT.java b/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectFrameworkRootIT.java deleted file mode 100644 index 03a1e12ce8820..0000000000000 --- a/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectFrameworkRootIT.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.quarkus.it.legacy.redirect; - -import io.quarkus.test.junit.NativeImageTest; - -@NativeImageTest -class LegacyRedirectFrameworkRootIT extends LegacyRedirectFrameworkRootTest { -} diff --git a/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectFrameworkRootTest.java b/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectFrameworkRootTest.java deleted file mode 100644 index e862e7e03fb91..0000000000000 --- a/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectFrameworkRootTest.java +++ /dev/null @@ -1,112 +0,0 @@ -package io.quarkus.it.legacy.redirect; - -import java.net.URL; -import java.util.HashMap; -import java.util.Map; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import io.quarkus.test.common.http.TestHTTPResource; -import io.quarkus.test.junit.QuarkusTest; -import io.quarkus.test.junit.QuarkusTestProfile; -import io.quarkus.test.junit.TestProfile; - -@QuarkusTest -@TestProfile(LegacyRedirectFrameworkRootTest.SetFrameworkRoot.class) -class LegacyRedirectFrameworkRootTest { - - // Legacy redirect behavior is implicitly scoped to the configured - // http root (i.e. /app/health will be redirected) - - public static class SetFrameworkRoot implements QuarkusTestProfile { - @Override - public Map getConfigOverrides() { - Map overrides = new HashMap<>(); - overrides.put("quarkus.http.root-path", "/app"); - overrides.put("quarkus.http.non-application-root-path", "/framework"); - return overrides; - } - } - - @TestHTTPResource(value = "/") - URL hostPortUrl; - - WebClientUtil clientUtil = new WebClientUtil(); - - @BeforeEach - void setUrl() { - clientUtil.setHostPortUrl(hostPortUrl); - } - - @Test - public void testGraphQlUnchangedNeverRedirect() { - // Not found: moved with application endpoint - clientUtil.validate("/graphql", 404); - // Not the same as 404.. graphql is found in the right place - clientUtil.validate("/app/graphql", 405); - } - - @Test - public void testGraphQlUiWithRedirect() { - // Not found: moved with application endpoint - clientUtil.validate("/graphql-ui", 404); - - clientUtil.validate("/app/graphql-ui", 301, "/framework/graphql-ui"); - clientUtil.validate("/framework/graphql-ui", 302); - } - - @Test - // TODO - MP4 - Require SR Health 3.0.1 - @Disabled - public void testHealthWithRedirect() { - // Not found: moved with application endpoint - clientUtil.validate("/health", 404); - - clientUtil.validate("/app/health", 301, "/framework/health"); - clientUtil.validate("/framework/health", 200); - - clientUtil.validate("/app/health/group", 301, "/framework/health/group"); - clientUtil.validate("/framework/health/group", 200); - - clientUtil.validate("/app/health/live", 301, "/framework/health/live"); - clientUtil.validate("/framework/health/live", 200); - - clientUtil.validate("/app/health/ready", 301, "/framework/health/ready"); - clientUtil.validate("/framework/health/ready", 200); - - clientUtil.validate("/app/health/well", 301, "/framework/health/well"); - clientUtil.validate("/framework/health/well", 200); - - clientUtil.validate("/app/health-ui", 301, "/framework/health-ui"); - clientUtil.validate("/framework/health-ui", 302); - } - - @Test - public void testMetricsWithRedirect() { - // Not found: moved with application endpoint - clientUtil.validate("/metrics", 404); - - clientUtil.validate("/app/metrics", 301, "/framework/metrics"); - clientUtil.validateText("/framework/metrics", 200); - } - - @Test - public void testOpenApiWithRedirect() { - // Not found: moved with application endpoint - clientUtil.validate("/openapi", 404); - - clientUtil.validate("/app/openapi", 301, "/framework/openapi"); - clientUtil.validate("/framework/openapi", 200); - } - - @Test - public void testSwaggerUiWithRedirect() { - // Not found: moved with application endpoint - clientUtil.validate("/swagger-ui", 404); - - clientUtil.validate("/app/swagger-ui", 301, "/framework/swagger-ui"); - clientUtil.validate("/framework/swagger-ui", 302); - } -} diff --git a/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectIT.java b/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectIT.java deleted file mode 100644 index 1edd1a26f4535..0000000000000 --- a/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectIT.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.quarkus.it.legacy.redirect; - -import io.quarkus.test.junit.NativeImageTest; - -@NativeImageTest -class LegacyRedirectIT extends LegacyRedirectTest { -} diff --git a/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectTest.java b/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectTest.java deleted file mode 100644 index 017c90fa89720..0000000000000 --- a/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/LegacyRedirectTest.java +++ /dev/null @@ -1,81 +0,0 @@ -package io.quarkus.it.legacy.redirect; - -import java.net.URL; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import io.quarkus.test.common.http.TestHTTPResource; -import io.quarkus.test.junit.QuarkusTest; - -@QuarkusTest -class LegacyRedirectTest { - - // Default configuration - - @TestHTTPResource(value = "/") - URL hostPortUrl; - - WebClientUtil clientUtil = new WebClientUtil(); - - @BeforeEach - void setUrl() { - clientUtil.setHostPortUrl(hostPortUrl); - } - - @Test - public void testGraphQlUnchangedNeverRedirect() { - // Not the same as 404.. graphql is found in the right place - clientUtil.validate("/graphql", 405); - } - - @Test - public void testGraphQlUiWithRedirect() { - clientUtil.validate("/graphql-ui", 301, "/q/graphql-ui"); - clientUtil.validate("/q/graphql-ui", 302); - } - - @Test - // TODO - MP4 - Require SR Health 3.0.1 - @Disabled - public void testHealthWithRedirect() { - clientUtil.validate("/health", 301, "/q/health"); - clientUtil.validate("/q/health", 200); - - clientUtil.validate("/health/group", 301, "/q/health/group"); - clientUtil.validate("/q/health/group", 200); - - clientUtil.validate("/health/live", 301, "/q/health/live"); - clientUtil.validate("/q/health/live", 200); - - clientUtil.validate("/health/ready", 301, "/q/health/ready"); - clientUtil.validate("/q/health/ready", 200); - - clientUtil.validate("/health/well", 301, "/q/health/well"); - clientUtil.validate("/q/health/well", 200); - - clientUtil.validate("/health-ui", 301, "/q/health-ui"); - clientUtil.validate("/q/health-ui", 302); - } - - @Test - public void testMetricsWithRedirect() { - clientUtil.validate("/metrics", 301, "/q/metrics"); - clientUtil.validateText("/q/metrics", 200); - } - - @Test - public void testOpenApiWithRedirect() { - clientUtil.validate("/openapi", 301, "/q/openapi"); - clientUtil.validate("/openapi?format=JSON", 301, "/q/openapi?format=JSON"); - clientUtil.validateContentType("/q/openapi?format=JSON", 200, "application/json"); - clientUtil.followForContentType("/openapi?format=JSON", 200, "application/json"); - } - - @Test - public void testSwaggerUiWithRedirect() { - clientUtil.validate("/swagger-ui", 301, "/q/swagger-ui"); - clientUtil.validate("/q/swagger-ui", 302); - } -} diff --git a/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/WebClientUtil.java b/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/WebClientUtil.java deleted file mode 100644 index f0ccb58e99aa2..0000000000000 --- a/integration-tests/legacy-redirect/src/test/java/io/quarkus/it/legacy/redirect/WebClientUtil.java +++ /dev/null @@ -1,123 +0,0 @@ -package io.quarkus.it.legacy.redirect; - -import java.net.URL; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -import org.junit.jupiter.api.Assertions; - -import io.vertx.core.Vertx; -import io.vertx.core.buffer.Buffer; -import io.vertx.ext.web.client.HttpRequest; -import io.vertx.ext.web.client.HttpResponse; -import io.vertx.ext.web.client.WebClient; -import io.vertx.ext.web.client.WebClientOptions; - -public class WebClientUtil { - - static class Result { - String requestedPath; - int statusCode; - String redirectPath; - String contentType; - - public String toString() { - return "requestedPath=" + requestedPath + ", statusCode=" + statusCode + ", redirectPath=" + redirectPath - + ", contentType=" + contentType; - } - } - - URL hostPortUrl; - - void setHostPortUrl(URL hostPortUrl) { - this.hostPortUrl = hostPortUrl; - } - - public void validate(String requestPath, int expectedStatusCode) { - internalValidate(requestPath, expectedStatusCode, null, null, false); - } - - public void validate(String requestPath, int expectedStatusCode, String expectedRedirect) { - internalValidate(requestPath, expectedStatusCode, expectedRedirect, null, false); - } - - public void validateText(String requestPath, int expectedStatusCode) { - internalValidate(requestPath, expectedStatusCode, null, "text/plain", false); - } - - public void validateText(String requestPath, int expectedStatusCode, String expectedRedirect) { - internalValidate(requestPath, expectedStatusCode, expectedRedirect, "text/plain", false); - } - - public void validateContentType(String requestPath, int expectedStatusCode, String contentType) { - WebClientUtil.Result result = internalValidate(requestPath, expectedStatusCode, null, null, false); - Assertions.assertTrue(result.contentType.startsWith(contentType), - "Expected Content-Type for request to path " + requestPath + " to start with " + contentType - + ", instead found " + result.contentType); - } - - public void followForContentType(String requestPath, int expectedStatusCode, String contentType) { - WebClientUtil.Result result = internalValidate(requestPath, expectedStatusCode, null, null, true); - Assertions.assertTrue(result.contentType.startsWith(contentType), - "Expected Content-Type for request to path " + requestPath + " to start with " + contentType - + ", instead found " + result.contentType); - } - - WebClientUtil.Result internalValidate(String requestPath, int expectedStatusCode, String expectedRedirect, - String acceptType, boolean follow) { - - WebClientUtil.Result result = get(requestPath, acceptType, follow); - - Assertions.assertEquals(expectedStatusCode, result.statusCode, - "Expected status code " + expectedStatusCode + " for request to path " + requestPath); - - if (expectedRedirect != null) { - Assertions.assertEquals(expectedRedirect, result.redirectPath, - "Expected a Location header value of " + expectedRedirect + " for request to path " + requestPath); - } - - return result; - } - - Result get(final String requestPath, final String acceptType, boolean follow) { - Vertx vertx = Vertx.vertx(); - - try { - CompletableFuture resultFuture = new CompletableFuture<>(); - - WebClientOptions options = new WebClientOptions() - .setFollowRedirects(follow); - - HttpRequest request = WebClient.create(vertx, options) - .get(hostPortUrl.getPort(), hostPortUrl.getHost(), requestPath); - - if (acceptType != null) { - request.putHeader("Accept", acceptType); - } - - request.send(ar -> { - if (ar.succeeded()) { - HttpResponse response = ar.result(); - Result result = new Result(); - result.requestedPath = requestPath; - result.statusCode = response.statusCode(); - result.contentType = response.getHeader("Content-Type"); - if (result.statusCode == 301) { - result.redirectPath = response.getHeader("Location"); - } - resultFuture.complete(result); - } else { - resultFuture.completeExceptionally(ar.cause()); - } - }); - - return resultFuture.get(); - } catch (InterruptedException | ExecutionException e) { - Assertions.fail(e); - return null; - } finally { - vertx.close(); - } - } - -} diff --git a/integration-tests/main/src/test/java/io/quarkus/it/main/HealthTestCase.java b/integration-tests/main/src/test/java/io/quarkus/it/main/HealthTestCase.java index 53d56a362c20b..5b4a84168daf4 100644 --- a/integration-tests/main/src/test/java/io/quarkus/it/main/HealthTestCase.java +++ b/integration-tests/main/src/test/java/io/quarkus/it/main/HealthTestCase.java @@ -54,46 +54,4 @@ public void testHealthCheck() { RestAssured.reset(); } } - - @Test - public void testHealthCheckRedirect() { - try { - RestAssured.when().get("/health/live").then() - .contentType(ContentType.JSON) - .header("Content-Type", containsString("charset=UTF-8")) - .body("status", is("UP"), - "checks.status", containsInAnyOrder("UP", "UP"), - "checks.name", containsInAnyOrder("basic", "basic-with-builder")); - - RestAssured.when().get("/health/ready").then() - .contentType(ContentType.JSON) - .header("Content-Type", containsString("charset=UTF-8")) - .body("status", is("UP"), - "checks.status", containsInAnyOrder("UP"), - "checks.name", containsInAnyOrder("Database connections health check")); - - RestAssured.when().get("/health/group/group1").then() - .contentType(ContentType.JSON) - .header("Content-Type", containsString("charset=UTF-8")) - .body("status", is("UP"), - "checks.status", containsInAnyOrder("UP", "UP"), - "checks.name", containsInAnyOrder("single", "combined")); - - RestAssured.when().get("/health/group/group2").then() - .contentType(ContentType.JSON) - .header("Content-Type", containsString("charset=UTF-8")) - .body("status", is("UP"), - "checks.status", containsInAnyOrder("UP"), - "checks.name", containsInAnyOrder("combined")); - - RestAssured.when().get("/health/group").then() - .contentType(ContentType.JSON) - .header("Content-Type", containsString("charset=UTF-8")) - .body("status", is("UP"), - "checks.status", containsInAnyOrder("UP", "UP"), - "checks.name", containsInAnyOrder("single", "combined")); - } finally { - RestAssured.reset(); - } - } } diff --git a/integration-tests/main/src/test/java/io/quarkus/it/main/SwaggerUITestCase.java b/integration-tests/main/src/test/java/io/quarkus/it/main/SwaggerUITestCase.java index 03e8b6144c3e4..b071242218629 100644 --- a/integration-tests/main/src/test/java/io/quarkus/it/main/SwaggerUITestCase.java +++ b/integration-tests/main/src/test/java/io/quarkus/it/main/SwaggerUITestCase.java @@ -17,11 +17,4 @@ public void testSwaggerUi() { .body(containsString("/openapi")); } - @Test - public void testSwaggerUiRedirect() { - RestAssured.when().get("/swagger-ui").then() - .body(containsString("#swagger-ui")) - .body(containsString("/openapi")); - } - } diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index e98fe39422ecd..8ba795d9150a1 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -67,7 +67,6 @@ hibernate-search-orm-elasticsearch hibernate-tenancy hibernate-orm-envers - legacy-redirect vertx-http vertx-web vertx-web-jackson diff --git a/integration-tests/smallrye-metrics/src/test/java/io/quarkus/it/metrics/MetricsTestCase.java b/integration-tests/smallrye-metrics/src/test/java/io/quarkus/it/metrics/MetricsTestCase.java index 3f4e20f9829ee..0ffc3daec8c7e 100644 --- a/integration-tests/smallrye-metrics/src/test/java/io/quarkus/it/metrics/MetricsTestCase.java +++ b/integration-tests/smallrye-metrics/src/test/java/io/quarkus/it/metrics/MetricsTestCase.java @@ -101,13 +101,6 @@ public void testScopes() { RestAssured.when().get("/q/metrics/application").then().statusCode(200); } - @Test - public void testScopesRedirect() { - RestAssured.when().get("/metrics/base").then().statusCode(200); - RestAssured.when().get("/metrics/vendor").then().statusCode(200); - RestAssured.when().get("/metrics/application").then().statusCode(200); - } - @Test public void testMetricWithAbsoluteName() { invokeCounterWithAbsoluteName(); From 788207ddd40e5c48557626e5114fb5efaccfcf0c Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Tue, 18 May 2021 11:18:57 +1000 Subject: [PATCH 0116/2077] Fix some test suite CL leaks - Stop TX Reaper thread - Start PU's in parallel - Clean up some static state --- .../quarkus/deployment/dev/DevModeMain.java | 2 ++ .../deployment/dev/IsolatedDevModeMain.java | 1 + .../dev/testing/JunitTestRunner.java | 6 +++- .../dev/console/DevConsoleManager.java | 8 +++++ .../hibernate/orm/runtime/JPAConfig.java | 33 ++++++++++++++++++- .../jta/deployment/NarayanaJtaProcessor.java | 4 ++- .../jta/runtime/NarayanaJtaRecorder.java | 11 +++++++ .../test/junit/QuarkusTestExtension.java | 1 + 8 files changed, 63 insertions(+), 3 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/DevModeMain.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/DevModeMain.java index e61c3419e76cb..45474e17abf00 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/DevModeMain.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/DevModeMain.java @@ -226,5 +226,7 @@ public void close() throws IOException { if (ApplicationStateNotification.getState() == ApplicationStateNotification.State.STARTED) { ApplicationStateNotification.waitForApplicationStop(); } + curatedApplication.close(); + curatedApplication = null; } } diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedDevModeMain.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedDevModeMain.java index 3da2424e11bba..cca7f17f59ab7 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedDevModeMain.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedDevModeMain.java @@ -309,6 +309,7 @@ public void close() { } } finally { try { + DevConsoleManager.close(); curatedApplication.close(); } finally { if (shutdownThread != null) { diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/JunitTestRunner.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/JunitTestRunner.java index 0a3b2a911ea27..59cfd67a5f0ad 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/JunitTestRunner.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/JunitTestRunner.java @@ -136,7 +136,8 @@ public void runTests() { ClassLoader old = Thread.currentThread().getContextClassLoader(); try (QuarkusClassLoader tcl = testApplication.createDeploymentClassLoader()) { Thread.currentThread().setContextClassLoader(tcl); - ((Consumer) tcl.loadClass(CurrentTestApplication.class.getName()).newInstance()).accept(testApplication); + Consumer currentTestAppConsumer = (Consumer) tcl.loadClass(CurrentTestApplication.class.getName()).newInstance(); + currentTestAppConsumer.accept(testApplication); try (DiscoveryResult quarkusTestClasses = discoverTestClasses(devModeContext)) { @@ -333,10 +334,13 @@ public void reportingEntryPublished(TestIdentifier testIdentifier, ReportEntry e listener.runComplete(new TestRunResults(runId, classScanResult, classScanResult == null, start, System.currentTimeMillis(), toResultsMap(historicFailures, resultsByClass))); } + } finally { + currentTestAppConsumer.accept(null); } } catch (Exception e) { throw new RuntimeException(e); } finally { + TracingHandler.setTracingHandler(null); QuarkusConsole.INSTANCE.setOutputFilter(null); Thread.currentThread().setContextClassLoader(old); } diff --git a/core/devmode-spi/src/main/java/io/quarkus/dev/console/DevConsoleManager.java b/core/devmode-spi/src/main/java/io/quarkus/dev/console/DevConsoleManager.java index 8495572d37f15..9648f1f78c5d6 100644 --- a/core/devmode-spi/src/main/java/io/quarkus/dev/console/DevConsoleManager.java +++ b/core/devmode-spi/src/main/java/io/quarkus/dev/console/DevConsoleManager.java @@ -79,4 +79,12 @@ public static void setGlobal(String name, Object value) { public static T getGlobal(String name) { return (T) globals.get(name); } + + public static void close() { + handler = null; + templateInfo = null; + hotReplacementContext = null; + quarkusBootstrap = null; + globals.clear(); + } } diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/JPAConfig.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/JPAConfig.java index a905ebda8648a..1b5fa1d0d75ae 100644 --- a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/JPAConfig.java +++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/JPAConfig.java @@ -1,10 +1,14 @@ package io.quarkus.hibernate.orm.runtime; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import javax.annotation.PreDestroy; import javax.enterprise.context.ApplicationScoped; @@ -38,8 +42,35 @@ public JPAConfig(JPAConfigSupport jpaConfigSupport) { } void startAll() { + List> start = new ArrayList<>(); + //start PU's in parallel, for faster startup + //also works around https://github.com/quarkusio/quarkus/issues/17304 to some extent + //as the main thread is now no longer polluted with ThreadLocals by default + //this is not a complete fix, but will help as long as the test methods + //don't access the datasource directly, but only over HTTP calls for (Map.Entry i : persistenceUnits.entrySet()) { - i.getValue().get(); + CompletableFuture future = new CompletableFuture<>(); + start.add(future); + new Thread(new Runnable() { + @Override + public void run() { + try { + i.getValue().get(); + future.complete(null); + } catch (Throwable t) { + future.completeExceptionally(t); + } + } + }, "JPA Startup Thread: " + i.getKey()).start(); + } + for (CompletableFuture i : start) { + try { + i.get(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } catch (ExecutionException e) { + throw new RuntimeException(e.getCause()); + } } } 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 12101103b74b5..89636ed839b3f 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 @@ -33,6 +33,7 @@ import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.annotations.Record; import io.quarkus.deployment.builditem.FeatureBuildItem; +import io.quarkus.deployment.builditem.ShutdownContextBuildItem; import io.quarkus.deployment.builditem.nativeimage.NativeImageSystemPropertyBuildItem; import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem; @@ -67,7 +68,8 @@ public void build(NarayanaJtaRecorder recorder, BuildProducer reflectiveClass, BuildProducer runtimeInit, BuildProducer feature, - TransactionManagerConfiguration transactions) { + TransactionManagerConfiguration transactions, ShutdownContextBuildItem shutdownContextBuildItem) { + recorder.handleShutdown(shutdownContextBuildItem); feature.produce(new FeatureBuildItem(Feature.NARAYANA_JTA)); additionalBeans.produce(new AdditionalBeanBuildItem(NarayanaJtaProducers.class)); additionalBeans.produce(new AdditionalBeanBuildItem(CDIDelegatingTransactionManager.class)); 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 65fef0bd65b9f..5c5267c2c9ddc 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 @@ -9,10 +9,12 @@ import com.arjuna.ats.arjuna.common.CoreEnvironmentBeanException; import com.arjuna.ats.arjuna.common.arjPropertyManager; +import com.arjuna.ats.arjuna.coordinator.TransactionReaper; import com.arjuna.ats.arjuna.coordinator.TxControl; import com.arjuna.ats.jta.common.jtaPropertyManager; import com.arjuna.common.util.propertyservice.PropertiesFactory; +import io.quarkus.runtime.ShutdownContext; import io.quarkus.runtime.annotations.Recorder; @Recorder @@ -71,4 +73,13 @@ public void disableTransactionStatusManager() { public void setConfig(final TransactionManagerConfiguration transactions) { arjPropertyManager.getObjectStoreEnvironmentBean().setObjectStoreDir(transactions.objectStoreDirectory); } + + public void handleShutdown(ShutdownContext context) { + context.addLastShutdownTask(new Runnable() { + @Override + public void run() { + TransactionReaper.terminate(false); + } + }); + } } diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java index 05e355a7ec8ef..b9b04a6c6abcb 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java @@ -1086,6 +1086,7 @@ public void close() { } catch (Throwable e) { log.error("Failed to shutdown Quarkus", e); } finally { + runningQuarkusApplication = null; try { if (QuarkusTestExtension.this.originalCl != null) { setCCL(QuarkusTestExtension.this.originalCl); From cf3c5b7a44762f666ad515b7774348e782b42503 Mon Sep 17 00:00:00 2001 From: Foivos Zakkak Date: Tue, 18 May 2021 10:26:27 +0300 Subject: [PATCH 0117/2077] Flyway: Fix Scanner constructor substitution for Flyway 7.9.0 --- .../io/quarkus/flyway/runtime/graal/ScannerSubstitutions.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/graal/ScannerSubstitutions.java b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/graal/ScannerSubstitutions.java index 1840d08819ff2..dc184d56affe1 100644 --- a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/graal/ScannerSubstitutions.java +++ b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/graal/ScannerSubstitutions.java @@ -19,8 +19,10 @@ public final class ScannerSubstitutions { @Substitute public ScannerSubstitutions(Class implementedInterface, Collection locations, ClassLoader classLoader, Charset encoding, + boolean detectEncoding, boolean stream, - ResourceNameCache resourceNameCache, LocationScannerCache locationScannerCache) { + ResourceNameCache resourceNameCache, LocationScannerCache locationScannerCache, + boolean throwOnMissingLocations) { throw new IllegalStateException("'org.flywaydb.core.internal.scanner.Scanner' is never used in Quarkus"); } } From 2115f5e1e1e2c9015486b199ef797f3709465ef2 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 18 May 2021 12:04:44 +0300 Subject: [PATCH 0118/2077] Fix double slash issue in not found page --- .../io/quarkus/resteasy/runtime/NotFoundExceptionMapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/NotFoundExceptionMapper.java b/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/NotFoundExceptionMapper.java index d8553592e98ba..ceddf459ba98b 100644 --- a/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/NotFoundExceptionMapper.java +++ b/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/NotFoundExceptionMapper.java @@ -179,7 +179,7 @@ public static List fromBoundResourceInvokers( if (basePath.endsWith("/")) { fullPath += subPath; } else { - fullPath = basePath + "/" + subPath; + fullPath = basePath + (subPath.startsWith("/") ? "" : "/") + subPath; } } description.addMethod(fullPath, method); From 8335e8a26bd7ec02247bf5ef6576e90cb1cc2ca0 Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Tue, 18 May 2021 11:21:29 +0200 Subject: [PATCH 0119/2077] Qute type-safe validation - various fixes - fix NPE when a loop element hint refers to a literal value - put bindings for iteration metadata inside a loop section; previously iteration metadata expressions together with type-safe templates caused a build failure by default --- .../qute/deployment/QuteProcessor.java | 55 ++++++++++++++----- .../CheckedTemplateRequireTypeSafeTest.java | 9 ++- .../java/io/quarkus/qute/ExpressionImpl.java | 4 +- .../java/io/quarkus/qute/Expressions.java | 4 ++ .../io/quarkus/qute/LoopSectionHelper.java | 9 +++ .../src/main/java/io/quarkus/qute/Parser.java | 4 +- 6 files changed, 65 insertions(+), 20 deletions(-) diff --git a/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/QuteProcessor.java b/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/QuteProcessor.java index df3a41d29277e..89968f5b683f7 100644 --- a/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/QuteProcessor.java +++ b/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/QuteProcessor.java @@ -1423,13 +1423,8 @@ static boolean processHints(TemplateAnalysis templateAnalysis, List help // Map => Entry processLoopElementHint(match, index, expression, incorrectExpressions); } else if (helperHint.startsWith(LoopSectionHelper.Factory.HINT_PREFIX)) { - Expression valueExpr = findExpression(helperHint, LoopSectionHelper.Factory.HINT_PREFIX, templateAnalysis); - if (valueExpr != null) { - Match valueExprMatch = generatedIdsToMatches.get(valueExpr.getGeneratedId()); - if (valueExprMatch != null) { - match.setValues(valueExprMatch.clazz, valueExprMatch.type); - } - } + setMatchValues(match, findExpression(helperHint, LoopSectionHelper.Factory.HINT_PREFIX, templateAnalysis), + generatedIdsToMatches, index); } else if (helperHint.startsWith(WhenSectionHelper.Factory.HINT_PREFIX)) { // If a value expression resolves to an enum we attempt to use the enum type to validate the enum constant // This basically transforms the type info "ON" into something like "|org.acme.Status|.ON" @@ -1442,16 +1437,48 @@ static boolean processHints(TemplateAnalysis templateAnalysis, List help } } } else if (helperHint.startsWith(SetSectionHelper.Factory.HINT_PREFIX)) { - Expression valueExpr = findExpression(helperHint, SetSectionHelper.Factory.HINT_PREFIX, templateAnalysis); - if (valueExpr != null) { - Match valueExprMatch = generatedIdsToMatches.get(valueExpr.getGeneratedId()); - if (valueExprMatch != null) { - match.setValues(valueExprMatch.clazz, valueExprMatch.type); + setMatchValues(match, findExpression(helperHint, SetSectionHelper.Factory.HINT_PREFIX, templateAnalysis), + generatedIdsToMatches, index); + } + } + return false; + } + + private static void setMatchValues(Match match, Expression valueExpr, Map generatedIdsToMatches, + IndexView index) { + if (valueExpr != null) { + if (valueExpr.isLiteral()) { + Object literalValue; + try { + literalValue = valueExpr.getLiteralValue().get(); + } catch (InterruptedException | ExecutionException e) { + literalValue = null; + } + if (literalValue == null) { + match.clearValues(); + } else { + if (literalValue instanceof Boolean) { + match.setValues(index.getClassByName(DotNames.BOOLEAN), Types.box(Primitive.BOOLEAN)); + } else if (literalValue instanceof String) { + match.setValues(index.getClassByName(DotNames.STRING), + Type.create(DotNames.STRING, org.jboss.jandex.Type.Kind.CLASS)); + } else if (literalValue instanceof Integer) { + match.setValues(index.getClassByName(DotNames.INTEGER), Types.box(Primitive.INT)); + } else if (literalValue instanceof Long) { + match.setValues(index.getClassByName(DotNames.LONG), Types.box(Primitive.LONG)); + } else if (literalValue instanceof Double) { + match.setValues(index.getClassByName(DotNames.DOUBLE), Types.box(Primitive.DOUBLE)); + } else if (literalValue instanceof Float) { + match.setValues(index.getClassByName(DotNames.FLOAT), Types.box(Primitive.FLOAT)); } } + } else { + Match valueExprMatch = generatedIdsToMatches.get(valueExpr.getGeneratedId()); + if (valueExprMatch != null) { + match.setValues(valueExprMatch.clazz, valueExprMatch.type); + } } } - return false; } private static Expression findExpression(String helperHint, String hintPrefix, TemplateAnalysis templateAnalysis) { @@ -1461,7 +1488,7 @@ private static Expression findExpression(String helperHint, String hintPrefix, T static void processLoopElementHint(Match match, IndexView index, Expression expression, BuildProducer incorrectExpressions) { - if (match.type().name().equals(DotNames.INTEGER)) { + if (match.isEmpty() || match.type().name().equals(DotNames.INTEGER)) { return; } Type matchType = null; diff --git a/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/typesafe/CheckedTemplateRequireTypeSafeTest.java b/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/typesafe/CheckedTemplateRequireTypeSafeTest.java index dc8ba97a3f49e..43247ae7b86bb 100644 --- a/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/typesafe/CheckedTemplateRequireTypeSafeTest.java +++ b/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/typesafe/CheckedTemplateRequireTypeSafeTest.java @@ -24,7 +24,14 @@ public class CheckedTemplateRequireTypeSafeTest { static final QuarkusUnitTest config = new QuarkusUnitTest() .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) .addClasses(Templates.class, Fool.class) - .addAsResource(new StringAsset("Hello {name}! {any} {inject:fool.getJoke(identifier)}"), + .addAsResource(new StringAsset( + "Hello {name}!" + + "{any} " + + "{inject:fool.getJoke(identifier)} " + + "{#each name.chars.iterator}" + + "{! {index} is not considered an error because the binding is registered by the loop section !}" + + "{index}. {it}" + + "{/each}"), "templates/CheckedTemplateRequireTypeSafeTest/hola.txt")) .assertException(t -> { Throwable e = t; diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/ExpressionImpl.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/ExpressionImpl.java index 7bc29bb0ba086..536bdadf1fb90 100644 --- a/independent-projects/qute/core/src/main/java/io/quarkus/qute/ExpressionImpl.java +++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/ExpressionImpl.java @@ -42,9 +42,7 @@ static ExpressionImpl literal(int id, String literal, Object value, Origin origi } return new ExpressionImpl(id, null, Collections.singletonList(new PartImpl(literal, - value != null - ? Expressions.TYPE_INFO_SEPARATOR + value.getClass().getName() + Expressions.TYPE_INFO_SEPARATOR - : null)), + value != null ? Expressions.typeInfoFrom(value.getClass().getName()) : null)), value, origin); } diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/Expressions.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/Expressions.java index 4d7d08cf5fc71..372372b101edd 100644 --- a/independent-projects/qute/core/src/main/java/io/quarkus/qute/Expressions.java +++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/Expressions.java @@ -140,6 +140,10 @@ public static List splitParts(String value, SplitConfig splitConfig) { return parts.build(); } + public static String typeInfoFrom(String typeName) { + return TYPE_INFO_SEPARATOR + typeName + TYPE_INFO_SEPARATOR; + } + /** * * @param buffer diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/LoopSectionHelper.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/LoopSectionHelper.java index 635ee43a7ea69..eb08f0caff3b9 100644 --- a/independent-projects/qute/core/src/main/java/io/quarkus/qute/LoopSectionHelper.java +++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/LoopSectionHelper.java @@ -172,6 +172,15 @@ public Scope initializeBlock(Scope previousScope, BlockInfo block) { alias = alias.equals(Parameter.EMPTY) ? DEFAULT_ALIAS : alias; Scope newScope = new Scope(previousScope); newScope.putBinding(alias, alias + HINT_PREFIX + iterableExpr.getGeneratedId() + ">"); + // Put bindings for iteration metadata + newScope.putBinding("count", Expressions.typeInfoFrom(Integer.class.getName())); + newScope.putBinding("index", Expressions.typeInfoFrom(Integer.class.getName())); + newScope.putBinding("indexParity", Expressions.typeInfoFrom(String.class.getName())); + newScope.putBinding("hasNext", Expressions.typeInfoFrom(Boolean.class.getName())); + newScope.putBinding("odd", Expressions.typeInfoFrom(Boolean.class.getName())); + newScope.putBinding("isOdd", Expressions.typeInfoFrom(Boolean.class.getName())); + newScope.putBinding("even", Expressions.typeInfoFrom(Boolean.class.getName())); + newScope.putBinding("isEven", Expressions.typeInfoFrom(Boolean.class.getName())); return newScope; } else { // Make sure we do not try to validate against the parent context diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/Parser.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/Parser.java index 69e792cf5965b..1187cee470808 100644 --- a/independent-projects/qute/core/src/main/java/io/quarkus/qute/Parser.java +++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/Parser.java @@ -479,7 +479,7 @@ private void flushTag() { int spaceIdx = content.indexOf(" "); String key = content.substring(spaceIdx + 1, content.length()); String value = content.substring(1, spaceIdx); - currentScope.putBinding(key, Expressions.TYPE_INFO_SEPARATOR + value + Expressions.TYPE_INFO_SEPARATOR); + currentScope.putBinding(key, Expressions.typeInfoFrom(value)); sectionStack.peek().currentBlock().addNode(new ParameterDeclarationNode(content, origin(0))); } else { // Expression @@ -989,7 +989,7 @@ public String getTemplateId() { public void addParameter(String name, String type) { // {@org.acme.Foo foo} Scope currentScope = scopeStack.peek(); - currentScope.putBinding(name, Expressions.TYPE_INFO_SEPARATOR + type + Expressions.TYPE_INFO_SEPARATOR); + currentScope.putBinding(name, Expressions.typeInfoFrom(type)); } @Override From 044720b4422a6328e29b81b435776b30f281f54f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 May 2021 09:43:13 +0000 Subject: [PATCH 0120/2077] Bump junit-bom from 5.7.1 to 5.7.2 Bumps [junit-bom](https://github.com/junit-team/junit5) from 5.7.1 to 5.7.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.7.1...r5.7.2) Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- independent-projects/arc/pom.xml | 2 +- independent-projects/bootstrap/pom.xml | 2 +- independent-projects/qute/pom.xml | 2 +- independent-projects/resteasy-reactive/pom.xml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 67b8d75b76676..bb15a0477c8aa 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -129,7 +129,7 @@ 11.5.5.0 1.2.6 4.3.3 - 5.7.1 + 5.7.2 6.14.2 3.19.0 2.3 diff --git a/independent-projects/arc/pom.xml b/independent-projects/arc/pom.xml index bc7f79c106918..14a9a303de810 100644 --- a/independent-projects/arc/pom.xml +++ b/independent-projects/arc/pom.xml @@ -39,7 +39,7 @@ 2.0.2 1.3.3 2.2.3.Final - 5.7.1 + 5.7.2 3.8.1 3.19.0 3.4.1.Final diff --git a/independent-projects/bootstrap/pom.xml b/independent-projects/bootstrap/pom.xml index 197b6b00298f4..88ae29b3e6bd7 100644 --- a/independent-projects/bootstrap/pom.xml +++ b/independent-projects/bootstrap/pom.xml @@ -27,7 +27,7 @@ 0.9.5 3.4.1.Final - 5.7.1 + 5.7.2 3.8.1 0.3.4 3.6.0 diff --git a/independent-projects/qute/pom.xml b/independent-projects/qute/pom.xml index dcb3ae03448b0..6c4c473fa9c9d 100644 --- a/independent-projects/qute/pom.xml +++ b/independent-projects/qute/pom.xml @@ -36,7 +36,7 @@ 11 11 11 - 5.7.1 + 5.7.2 1.0.8.Final 3.4.1.Final 3.0.0-M5 diff --git a/independent-projects/resteasy-reactive/pom.xml b/independent-projects/resteasy-reactive/pom.xml index e99b047f44088..eae63fa065a3c 100644 --- a/independent-projects/resteasy-reactive/pom.xml +++ b/independent-projects/resteasy-reactive/pom.xml @@ -38,7 +38,7 @@ 2.0.2 2.2.3.Final - 5.7.1 + 5.7.2 3.8.1 3.19.0 3.4.1.Final From c97aa9dded0926a642680c27ecf859bf51f2e1e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Tue, 18 May 2021 11:56:07 +0200 Subject: [PATCH 0121/2077] Configure GitHub Actions concurrency See https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#concurrency for the documentation of this feature. Essentially, this gives the following behavior: * For pull requests, only the most recent HEAD gets built. Builds for previous HEADs get cancelled automatically. * For branches (main, ...), we can only ever have two concurrent builds: one running, and one (more recent) pending. If a build is running and another one gets requested (because of a push), the second one will be pending and wait for the first one to finish. If a third build gets requested before the first one finishes, the second build gets cancelled and the third build will be pending until the first build finishes. --- .github/workflows/ci-actions-incremental.yml | 4 ++++ .github/workflows/ci-actions.yml.disabled | 4 ++++ .github/workflows/ci-fork-mvn-cache.yml | 4 ++++ .github/workflows/doc-build.yml | 3 +++ 4 files changed, 15 insertions(+) diff --git a/.github/workflows/ci-actions-incremental.yml b/.github/workflows/ci-actions-incremental.yml index 9b20f65d172e8..2d4cddabdebec 100644 --- a/.github/workflows/ci-actions-incremental.yml +++ b/.github/workflows/ci-actions-incremental.yml @@ -33,6 +33,10 @@ on: - '.github/*.conf' workflow_dispatch: +concurrency: + group: "workflow = ${{ github.workflow }}, ref = ${{ github.event.ref }}, pr = ${{ github.event.pull_request.id }}" + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + env: # Workaround testsuite locale issue LANG: en_US.UTF-8 diff --git a/.github/workflows/ci-actions.yml.disabled b/.github/workflows/ci-actions.yml.disabled index ac0d2ed5d5347..15d85f63f428a 100644 --- a/.github/workflows/ci-actions.yml.disabled +++ b/.github/workflows/ci-actions.yml.disabled @@ -30,6 +30,10 @@ on: - '.github/*.java' - '.github/*.conf' +concurrency: + group: "workflow = ${{ github.workflow }}, ref = ${{ github.event.ref }}, pr = ${{ github.event.pull_request.id }}" + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + env: # Workaround testsuite locale issue LANG: en_US.UTF-8 diff --git a/.github/workflows/ci-fork-mvn-cache.yml b/.github/workflows/ci-fork-mvn-cache.yml index 65b432ff9625b..1335136aebe24 100644 --- a/.github/workflows/ci-fork-mvn-cache.yml +++ b/.github/workflows/ci-fork-mvn-cache.yml @@ -21,6 +21,10 @@ on: # first day of month at 12:10am - cron: '10 0 1 * *' +concurrency: + group: "workflow = ${{ github.workflow }}, ref = ${{ github.event.ref }}, pr = ${{ github.event.pull_request.id }}" + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + env: LANG: en_US.UTF-8 jobs: diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index abb2d004bca6a..949a1848bde8c 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -10,6 +10,9 @@ on: - 'docs/src/main/asciidoc/**' - '.github/workflows/doc-build.yml' +concurrency: + group: "workflow = ${{ github.workflow }}, ref = ${{ github.event.ref }}, pr = ${{ github.event.pull_request.id }}" + cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: ci-sanity-check: From 5e672e7de3736d79d80add38ddfc6c9129efd856 Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Mon, 17 May 2021 12:27:49 +0200 Subject: [PATCH 0122/2077] Qute - introduce Eval section - to parse and evaluate templates dynamically - resolves #12792 --- docs/src/main/asciidoc/qute-reference.adoc | 18 ++++ .../java/io/quarkus/qute/EngineBuilder.java | 2 +- .../io/quarkus/qute/EvalSectionHelper.java | 99 +++++++++++++++++++ .../io/quarkus/qute/SectionHelperFactory.java | 4 + .../io/quarkus/qute/SetSectionHelper.java | 2 +- .../test/java/io/quarkus/qute/EvalTest.java | 50 ++++++++++ 6 files changed, 173 insertions(+), 2 deletions(-) create mode 100644 independent-projects/qute/core/src/main/java/io/quarkus/qute/EvalSectionHelper.java create mode 100644 independent-projects/qute/core/src/test/java/io/quarkus/qute/EvalTest.java diff --git a/docs/src/main/asciidoc/qute-reference.adoc b/docs/src/main/asciidoc/qute-reference.adoc index 3c2ec9ab76895..22b051b208a4d 100644 --- a/docs/src/main/asciidoc/qute-reference.adoc +++ b/docs/src/main/asciidoc/qute-reference.adoc @@ -865,6 +865,24 @@ Template inheritance makes it possible to reuse template layouts. NOTE: Section blocks can also define an optional end tag - `{/title}`. +==== Eval Section + +This section can be used to parse and evaluate a template dynamically. +The behavior is very similar to the <> but: + +1. The template content is passed directly, i.e. not obtained via an `io.quarkus.qute.TemplateLocator`, +2. It's not possible to override parts of the evaluated template. + +[source,html] +---- +{#eval myData.template name='Mia' /} <1><2><3> +---- +<1> The result of `myData.template` will be used as the template. The template is executed with the <>, i.e. can reference data from the template it's included into. +<2> It's also possible to define optional parameters that can be used in the evaluated template. +<3> The content of the section is always ignored. + +NOTE: The evaluated template is parsed and evaluated every time the section is executed. In other words, it's not possible to cache the parsed value to conserve resources and optimize the performance. + [[user_tags]] ==== User-defined Tags diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/EngineBuilder.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/EngineBuilder.java index c70c346ab9b4a..250ab197c6d0e 100644 --- a/independent-projects/qute/core/src/main/java/io/quarkus/qute/EngineBuilder.java +++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/EngineBuilder.java @@ -54,7 +54,7 @@ public EngineBuilder addSectionHelper(String name, SectionHelperFactory facto public EngineBuilder addDefaultSectionHelpers() { return addSectionHelpers(new IfSectionHelper.Factory(), new LoopSectionHelper.Factory(), new WithSectionHelper.Factory(), new IncludeSectionHelper.Factory(), new InsertSectionHelper.Factory(), - new SetSectionHelper.Factory(), new WhenSectionHelper.Factory()); + new SetSectionHelper.Factory(), new WhenSectionHelper.Factory(), new EvalSectionHelper.Factory()); } public EngineBuilder addValueResolver(Supplier resolverSupplier) { diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/EvalSectionHelper.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/EvalSectionHelper.java new file mode 100644 index 0000000000000..403eb4e429477 --- /dev/null +++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/EvalSectionHelper.java @@ -0,0 +1,99 @@ +package io.quarkus.qute; + +import static io.quarkus.qute.Futures.evaluateParams; + +import io.quarkus.qute.TemplateNode.Origin; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +public class EvalSectionHelper implements SectionHelper { + + private static final String TEMPLATE = "template"; + + private final Map parameters; + private final Engine engine; + + public EvalSectionHelper(Map parameters, Engine engine) { + this.parameters = parameters; + this.engine = engine; + } + + @Override + public CompletionStage resolve(SectionResolutionContext context) { + CompletableFuture result = new CompletableFuture<>(); + evaluateParams(parameters, context.resolutionContext()).whenComplete((evaluatedParams, t1) -> { + if (t1 != null) { + result.completeExceptionally(t1); + } else { + try { + // Parse the template and execute with the params as the root context object + String templateStr = evaluatedParams.get(TEMPLATE).toString(); + TemplateImpl template; + try { + template = (TemplateImpl) engine.parse(templateStr); + } catch (TemplateException e) { + Origin origin = parameters.get(TEMPLATE).getOrigin(); + StringBuilder builder = new StringBuilder("Parser error in the evaluated template"); + if (!origin.getTemplateId().equals(origin.getTemplateGeneratedId())) { + builder.append(" in template [").append(origin.getTemplateId()).append("]"); + } + builder.append(" on line ").append(origin.getLine()).append(":\n\t") + .append(e.getMessage()); + throw new TemplateException(parameters.get(TEMPLATE).getOrigin(), + builder.toString()); + } + template.root + .resolve(context.resolutionContext().createChild(Mapper.wrap(evaluatedParams), null)) + .whenComplete((resultNode, t2) -> { + if (t2 != null) { + result.completeExceptionally(t2); + } else { + result.complete(resultNode); + } + }); + } catch (Throwable e) { + result.completeExceptionally(e); + } + } + }); + return result; + } + + public static class Factory implements SectionHelperFactory { + + @Override + public List getDefaultAliases() { + return ImmutableList.of("eval"); + } + + @Override + public ParametersInfo getParameters() { + return ParametersInfo.builder().addParameter(TEMPLATE).build(); + } + + @Override + public EvalSectionHelper initialize(SectionInitContext context) { + Map params = new HashMap<>(); + for (Entry entry : context.getParameters().entrySet()) { + params.put(entry.getKey(), context.getExpression(entry.getKey())); + } + return new EvalSectionHelper(params, context.getEngine()); + } + + @Override + public Scope initializeBlock(Scope outerScope, BlockInfo block) { + if (block.getLabel().equals(MAIN_BLOCK_NAME)) { + for (Entry entry : block.getParameters().entrySet()) { + block.addExpression(entry.getKey(), entry.getValue()); + } + } + return outerScope; + } + + } + +} diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/SectionHelperFactory.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/SectionHelperFactory.java index 3862f02e0f573..f644ff3241b7c 100644 --- a/independent-projects/qute/core/src/main/java/io/quarkus/qute/SectionHelperFactory.java +++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/SectionHelperFactory.java @@ -91,6 +91,8 @@ default boolean hasParameter(String name) { /** * Parse and register an expression for the specified parameter. + *

+ * A registered expression contributes to the {@link Template#getExpressions()}, i.e. can be validated at build time. * * @param param * @param value @@ -123,6 +125,8 @@ default public String getParameter(String name) { } /** + * Note that the expression must be registered in the {@link SectionHelperFactory#initializeBlock(Scope, BlockInfo)} + * first. * * @param parameterName * @return an expression registered for the specified param name, or {@code null} diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/SetSectionHelper.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/SetSectionHelper.java index a35663a29d979..d88fc1e0c7793 100644 --- a/independent-projects/qute/core/src/main/java/io/quarkus/qute/SetSectionHelper.java +++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/SetSectionHelper.java @@ -60,7 +60,7 @@ public ParametersInfo getParameters() { @Override public SetSectionHelper initialize(SectionInitContext context) { Map params = context.getParameters().entrySet().stream() - .collect(Collectors.toMap(e -> e.getKey(), e -> context.parseValue(e.getValue()))); + .collect(Collectors.toMap(e -> e.getKey(), e -> context.getExpression(e.getKey()))); return new SetSectionHelper(params); } diff --git a/independent-projects/qute/core/src/test/java/io/quarkus/qute/EvalTest.java b/independent-projects/qute/core/src/test/java/io/quarkus/qute/EvalTest.java new file mode 100644 index 0000000000000..c789438199ae2 --- /dev/null +++ b/independent-projects/qute/core/src/test/java/io/quarkus/qute/EvalTest.java @@ -0,0 +1,50 @@ +package io.quarkus.qute; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import org.junit.jupiter.api.Test; + +public class EvalTest { + + @Test + public void testEval() { + Engine engine = Engine.builder().addDefaults().build(); + assertEquals("Hello Foo!", + engine.parse("{#eval 'Hello Foo!' /}").render()); + assertEquals("Hello Foo!", + engine.parse("{#eval 'Hello Foo!'}ignored!{/eval}").render()); + assertEquals("Hello Lu!", + engine.parse("{#eval foo /}").data("foo", "Hello {bar}!", "bar", "Lu").render()); + assertEquals("Hello Lu!", + engine.parse("{#eval foo /}").data("foo", "Hello {#eval bar /}!", "bar", "Lu").render()); + assertEquals("Hello Foo and true!", + engine.parse("{#eval name='Foo' template='Hello {name} and {bar}!' /}").data("bar", true).render()); + assertEquals("Hello Foo and true!", + engine.parse("{#eval template name='Foo' /}").data("template", "Hello {name} and {bar}!", "bar", true) + .render()); + } + + @Test + public void testTemplateParamNotSet() { + try { + Engine.builder().addDefaults().build().parse("{#eval name='Foo' /}"); + fail(); + } catch (TemplateException expected) { + assertTrue(expected.getMessage().contains("Parser error")); + assertTrue(expected.getMessage().contains("mandatory section parameters not declared")); + } + } + + @Test + public void testInvalidTemplateContents() { + try { + Engine.builder().addDefaults().build().parse("{#eval invalid /}").data("invalid", "{foo").render(); + fail(); + } catch (TemplateException expected) { + assertTrue(expected.getMessage().contains("Parser error in the evaluated template")); + } + } + +} From a006e6b365f821f9a0d5675864c3887a26bc23aa Mon Sep 17 00:00:00 2001 From: Falko Modler Date: Tue, 18 May 2021 14:12:27 +0200 Subject: [PATCH 0123/2077] CI incremental: fix insufficent number of native builds due to internal grep error --- .github/filter-native-tests-json.sh | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/filter-native-tests-json.sh b/.github/filter-native-tests-json.sh index ab44408c4d590..050037afb2cf6 100755 --- a/.github/filter-native-tests-json.sh +++ b/.github/filter-native-tests-json.sh @@ -22,21 +22,20 @@ fi # Step 1: build an expression for grep that will only extract the given modules from each "test-modules" list, # including a trailing comma (if exists). Note: mvn doesn't mind something like -pl 'foo,'. -EXPR='(' +EXPR='((?:(?<=^)|(?<=,)|(?<=, ))(' while read -r impacted do - EXPR+="((?<=^)|(?<=,)|(?<=, ))${impacted}(,|$)|" + EXPR+="${impacted}|" done < <(echo -n "$1" | grep -Po '(?<=integration-tests/).+') -EXPR+=')' +EXPR+=')(,|$))+' # Step 2: apply the filter expression via grep to each "test-modules" list and replace each original list with the filtered one while read -r modules do - # Note: switch off pipefail briefly to avoid failing when nothing matches - set +o pipefail - # Note: paste joins all matches to get a single line - FILTERED=$(echo -n "${modules}" | grep -Po "${EXPR}" | paste -sd " " -) - set -o pipefail + # Notes: + # - trailing "|" (after EXPR) avoids grep return code > 0 if nothing matches (which is a valid case) + # - "paste" joins all matches to get a single line + FILTERED=$(echo -n "${modules}" | grep -Po "${EXPR}|" | paste -sd " " -) JSON=$(echo -n "${JSON}" | sed "s|${modules}|${FILTERED}|") done < <(echo -n "${JSON}" | jq -r '.include[] | ."test-modules"') From d90dfe97df17db0c06dfbffd4a6edb29d39ecb5a Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Fri, 14 May 2021 18:58:20 +0100 Subject: [PATCH 0124/2077] Support Keycloak Authorization for OIDC web-app applications --- .../security-keycloak-authorization.adoc | 32 +++++++--- .../KeycloakPolicyEnforcerRecorder.java | 10 ++- .../keycloak-authorization/pom.xml | 5 ++ .../it/keycloak/CustomTenantResolver.java | 3 + .../ProtectedWebAppTenantResource.java | 34 ++++++++++ .../src/main/resources/application.properties | 22 ++++--- .../it/keycloak/KeycloakTestResource.java | 13 +++- .../it/keycloak/PolicyEnforcerTest.java | 64 ++++++++++++++++++- 8 files changed, 158 insertions(+), 25 deletions(-) create mode 100644 integration-tests/keycloak-authorization/src/main/java/io/quarkus/it/keycloak/ProtectedWebAppTenantResource.java diff --git a/docs/src/main/asciidoc/security-keycloak-authorization.adoc b/docs/src/main/asciidoc/security-keycloak-authorization.adoc index ec28dce507fb9..b6bc74fa470b6 100644 --- a/docs/src/main/asciidoc/security-keycloak-authorization.adoc +++ b/docs/src/main/asciidoc/security-keycloak-authorization.adoc @@ -189,7 +189,7 @@ quarkus.oidc.tls.verification=none quarkus.keycloak.policy-enforcer.enable=true ---- -NOTE: By default, applications using the `quarkus-oidc` extension are marked as a `service` type application (see `quarkus.oidc.application-type`). This extension currently supports only such `service` type applications. +NOTE: By default, applications using the `quarkus-oidc` extension are marked as a `service` type application (see `quarkus.oidc.application-type`). This extension also supports only `web-app` type applications but only if the access token returned as part of the authorization code grant response is marked as a source of roles: `quarkus.oidc.roles.source=accesstoken` (`web-app` type applications check ID token roles by default). == Starting and Configuring the Keycloak Server @@ -408,16 +408,30 @@ quarkus.keycloak.policy-enforcer.paths.1.name=Permission Resource quarkus.keycloak.policy-enforcer.paths.1.path=/api/permission quarkus.keycloak.policy-enforcer.paths.1.claim-information-point.claims.static-claim=static-claim -# Tenant1 +# Service Tenant -quarkus.oidc.tenant1.auth-server-url=${keycloak.url}/realms/quarkus -quarkus.oidc.tenant1.client-id=quarkus-app -quarkus.oidc.tenant1.credentials.secret=secret +quarkus.oidc.service-tenant.auth-server-url=${keycloak.url}/realms/quarkus +quarkus.oidc.service-tenant.client-id=quarkus-app +quarkus.oidc.service-tenant.credentials.secret=secret -quarkus.keycloak.tenant1.policy-enforcer.enforcement-mode=PERMISSIVE -quarkus.keycloak.tenant1.policy-enforcer.paths.1.name=Permission Resource -quarkus.keycloak.tenant1.policy-enforcer.paths.1.path=/api/permission -quarkus.keycloak.tenant1.policy-enforcer.paths.1.claim-information-point.claims.static-claim=static-claim +quarkus.keycloak.service-tenant.policy-enforcer.enforcement-mode=PERMISSIVE +quarkus.keycloak.service-tenant.policy-enforcer.paths.1.name=Permission Resource Service +quarkus.keycloak.service-tenant.policy-enforcer.paths.1.path=/api/permission +quarkus.keycloak.service-tenant.policy-enforcer.paths.1.claim-information-point.claims.static-claim=static-claim + + +# WebApp Tenant + +quarkus.oidc.webapp-tenant.auth-server-url=${keycloak.url}/realms/quarkus +quarkus.oidc.webapp-tenant.client-id=quarkus-app +quarkus.oidc.webapp-tenant.credentials.secret=secret +quarkus.oidc.webapp-tenant.application-type=web-app +quarkus.oidc.webapp-tenant.roles.source=accesstoken + +quarkus.keycloak.webapp-tenant.policy-enforcer.enforcement-mode=PERMISSIVE +quarkus.keycloak.webapp-tenant.policy-enforcer.paths.1.name=Permission Resource WebApp +quarkus.keycloak.webapp-tenant.policy-enforcer.paths.1.path=/api/permission +quarkus.keycloak.webapp-tenant.policy-enforcer.paths.1.claim-information-point.claims.static-claim=static-claim ---- == Configuration Reference diff --git a/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerRecorder.java b/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerRecorder.java index 47a4fef63b0a5..1cdf8e6d730df 100644 --- a/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerRecorder.java +++ b/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerRecorder.java @@ -15,6 +15,7 @@ import io.quarkus.keycloak.pep.runtime.KeycloakPolicyEnforcerTenantConfig.KeycloakConfigPolicyEnforcer.PathCacheConfig; import io.quarkus.oidc.OIDCException; import io.quarkus.oidc.OidcTenantConfig; +import io.quarkus.oidc.OidcTenantConfig.Roles.Source; import io.quarkus.oidc.common.runtime.OidcCommonConfig.Tls.Verification; import io.quarkus.oidc.runtime.OidcConfig; import io.quarkus.runtime.TlsConfig; @@ -27,9 +28,6 @@ public class KeycloakPolicyEnforcerRecorder { public Supplier setup(OidcConfig oidcConfig, KeycloakPolicyEnforcerConfig config, TlsConfig tlsConfig, HttpConfiguration httpConfiguration) { - if (oidcConfig.defaultTenant.applicationType == OidcTenantConfig.ApplicationType.WEB_APP) { - throw new OIDCException("Application type [" + oidcConfig.defaultTenant.applicationType + "] is not supported"); - } PolicyEnforcer defaultPolicyEnforcer = createPolicyEnforcer(oidcConfig.defaultTenant, config.defaultTenant, tlsConfig, httpConfiguration); Map policyEnforcerTenants = new HashMap(); @@ -53,6 +51,12 @@ public PolicyEnforcerResolver get() { private static PolicyEnforcer createPolicyEnforcer(OidcTenantConfig oidcConfig, KeycloakPolicyEnforcerTenantConfig keycloakPolicyEnforcerConfig, TlsConfig tlsConfig, HttpConfiguration httpConfiguration) { + + if (oidcConfig.applicationType == OidcTenantConfig.ApplicationType.WEB_APP + && oidcConfig.roles.source.orElse(null) != Source.accesstoken) { + throw new OIDCException("Application 'web-app' type is only supported if access token is the source of roles"); + } + AdapterConfig adapterConfig = new AdapterConfig(); String authServerUrl = oidcConfig.getAuthServerUrl().get(); diff --git a/integration-tests/keycloak-authorization/pom.xml b/integration-tests/keycloak-authorization/pom.xml index 054b0d8db6603..665c3f3920489 100644 --- a/integration-tests/keycloak-authorization/pom.xml +++ b/integration-tests/keycloak-authorization/pom.xml @@ -117,6 +117,11 @@ + + net.sourceforge.htmlunit + htmlunit + test + diff --git a/integration-tests/keycloak-authorization/src/main/java/io/quarkus/it/keycloak/CustomTenantResolver.java b/integration-tests/keycloak-authorization/src/main/java/io/quarkus/it/keycloak/CustomTenantResolver.java index d93d10cf49e60..ccf7348b98213 100644 --- a/integration-tests/keycloak-authorization/src/main/java/io/quarkus/it/keycloak/CustomTenantResolver.java +++ b/integration-tests/keycloak-authorization/src/main/java/io/quarkus/it/keycloak/CustomTenantResolver.java @@ -13,6 +13,9 @@ public String resolve(RoutingContext context) { if (context.request().path().endsWith("tenant")) { return "tenant"; } + if (context.request().path().endsWith("webapp")) { + return "webapp-tenant"; + } return null; } diff --git a/integration-tests/keycloak-authorization/src/main/java/io/quarkus/it/keycloak/ProtectedWebAppTenantResource.java b/integration-tests/keycloak-authorization/src/main/java/io/quarkus/it/keycloak/ProtectedWebAppTenantResource.java new file mode 100644 index 0000000000000..4af71b4da7fef --- /dev/null +++ b/integration-tests/keycloak-authorization/src/main/java/io/quarkus/it/keycloak/ProtectedWebAppTenantResource.java @@ -0,0 +1,34 @@ +package io.quarkus.it.keycloak; + +import java.util.List; + +import javax.inject.Inject; +import javax.security.auth.AuthPermission; +import javax.ws.rs.ForbiddenException; +import javax.ws.rs.GET; +import javax.ws.rs.Path; + +import org.keycloak.representations.idm.authorization.Permission; + +import io.quarkus.security.Authenticated; +import io.quarkus.security.identity.SecurityIdentity; +import io.smallrye.mutiny.Uni; + +@Path("/api-permission-webapp") +@Authenticated +public class ProtectedWebAppTenantResource { + + @Inject + SecurityIdentity identity; + + @GET + public Uni> permissions() { + return identity.checkPermission(new AuthPermission("Permission Resource WebApp")).onItem() + .transform(granted -> { + if (granted) { + return identity.getAttribute("permissions"); + } + throw new ForbiddenException(); + }); + } +} diff --git a/integration-tests/keycloak-authorization/src/main/resources/application.properties b/integration-tests/keycloak-authorization/src/main/resources/application.properties index 09c53bc71c420..7838065332e16 100644 --- a/integration-tests/keycloak-authorization/src/main/resources/application.properties +++ b/integration-tests/keycloak-authorization/src/main/resources/application.properties @@ -59,22 +59,24 @@ quarkus.keycloak.policy-enforcer.paths.10.enforcement-mode=ENFORCING quarkus.keycloak.policy-enforcer.paths.11.path=/api/public-token quarkus.keycloak.policy-enforcer.paths.11.enforcement-mode=DISABLED -# Tenant - +# Service Tenant quarkus.oidc.tenant.auth-server-url=${keycloak.url}/realms/quarkus quarkus.oidc.tenant.client-id=quarkus-app quarkus.oidc.tenant.credentials.secret=secret -# Enable Policy Enforcement -quarkus.keycloak.tenant.policy-enforcer.enforcement-mode=PERMISSIVE - -# Defines a global claim to be sent to Keycloak when evaluating permissions for any requesting coming to the application -quarkus.keycloak.tenant.policy-enforcer.claim-information-point.claims.request-uri={request.relativePath} -quarkus.keycloak.tenant.policy-enforcer.claim-information-point.claims.request-method={request.method} - -# Defines a static claim that is only sent to Keycloak when evaluating permissions for a specific path quarkus.keycloak.tenant.policy-enforcer.paths.1.name=Permission Resource Tenant quarkus.keycloak.tenant.policy-enforcer.paths.1.path=/api-permission-tenant quarkus.keycloak.tenant.policy-enforcer.paths.1.claim-information-point.claims.static-claim=static-claim +# Web App Tenant +quarkus.oidc.webapp-tenant.auth-server-url=${keycloak.url}/realms/quarkus +quarkus.oidc.webapp-tenant.client-id=quarkus-app +quarkus.oidc.webapp-tenant.credentials.secret=secret +quarkus.oidc.webapp-tenant.application-type=web-app +quarkus.oidc.webapp-tenant.roles.source=accesstoken + +quarkus.keycloak.webapp-tenant.policy-enforcer.paths.1.name=Permission Resource WebApp +quarkus.keycloak.webapp-tenant.policy-enforcer.paths.1.path=/api-permission-webapp +quarkus.keycloak.webapp-tenant.policy-enforcer.paths.1.claim-information-point.claims.static-claim=static-claim + admin-url=${keycloak.url} \ No newline at end of file diff --git a/integration-tests/keycloak-authorization/src/test/java/io/quarkus/it/keycloak/KeycloakTestResource.java b/integration-tests/keycloak-authorization/src/test/java/io/quarkus/it/keycloak/KeycloakTestResource.java index 687a5b45ae4f2..2e96a7112e447 100644 --- a/integration-tests/keycloak-authorization/src/test/java/io/quarkus/it/keycloak/KeycloakTestResource.java +++ b/integration-tests/keycloak-authorization/src/test/java/io/quarkus/it/keycloak/KeycloakTestResource.java @@ -35,7 +35,7 @@ public Map start() { RealmRepresentation realm = createRealm(KEYCLOAK_REALM); realm.getClients().add(createClient("quarkus-app")); - realm.getUsers().add(createUser("alice", "user")); + realm.getUsers().add(createUser("alice", "user", "superuser")); realm.getUsers().add(createUser("admin", "user", "admin")); realm.getUsers().add(createUser("jdoe", "user", "confidential")); @@ -66,6 +66,7 @@ private static RealmRepresentation createRealm(String name) { realm.setRoles(roles); realm.getRoles().getRealm().add(new RoleRepresentation("user", null, false)); + realm.getRoles().getRealm().add(new RoleRepresentation("superuser", null, false)); realm.getRoles().getRealm().add(new RoleRepresentation("admin", null, false)); realm.getRoles().getRealm().add(new RoleRepresentation("confidential", null, false)); @@ -76,6 +77,7 @@ private static ClientRepresentation createClient(String clientId) { ClientRepresentation client = new ClientRepresentation(); client.setClientId(clientId); + client.setRedirectUris(Arrays.asList("*")); client.setPublicClient(false); client.setSecret("secret"); client.setDirectAccessGrantsEnabled(true); @@ -118,6 +120,15 @@ private static void configurePermissionResourcePermission(ResourceServerRepresen createPermission(settings, createResource(settings, "Permission Resource Tenant", "/api-permission-tenant"), policyAdmin); + + PolicyRepresentation policyUser = createJSPolicy("Superuser Policy", "var identity = $evaluation.context.identity;\n" + + "\n" + + "if (identity.hasRealmRole(\"superuser\")) {\n" + + "$evaluation.grant();\n" + + "}", settings); + + createPermission(settings, createResource(settings, "Permission Resource WebApp", "/api-permission-webapp"), + policyUser); } private static void configureScopePermission(ResourceServerRepresentation settings) { diff --git a/integration-tests/keycloak-authorization/src/test/java/io/quarkus/it/keycloak/PolicyEnforcerTest.java b/integration-tests/keycloak-authorization/src/test/java/io/quarkus/it/keycloak/PolicyEnforcerTest.java index aa5d85fd28321..7194632cb3fad 100644 --- a/integration-tests/keycloak-authorization/src/test/java/io/quarkus/it/keycloak/PolicyEnforcerTest.java +++ b/integration-tests/keycloak-authorization/src/test/java/io/quarkus/it/keycloak/PolicyEnforcerTest.java @@ -1,5 +1,9 @@ package io.quarkus.it.keycloak; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + import java.io.IOException; import org.hamcrest.Matchers; @@ -8,6 +12,13 @@ import org.junit.jupiter.api.Test; import org.keycloak.representations.AccessTokenResponse; +import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; +import com.gargoylesoftware.htmlunit.SilentCssErrorHandler; +import com.gargoylesoftware.htmlunit.WebClient; +import com.gargoylesoftware.htmlunit.WebResponse; +import com.gargoylesoftware.htmlunit.html.HtmlForm; +import com.gargoylesoftware.htmlunit.html.HtmlPage; + import io.quarkus.test.junit.QuarkusTest; import io.restassured.RestAssured; import io.restassured.http.ContentType; @@ -30,7 +41,7 @@ public static void removeKeycloakRealm() { } @Test - public void testUserHasRoleConfidentialTenant() { + public void testUserHasAdminRoleServiceTenant() { RestAssured.given().auth().oauth2(getAccessToken("alice")) .when().get("/api-permission-tenant") .then() @@ -44,7 +55,56 @@ public void testUserHasRoleConfidentialTenant() { .then() .statusCode(200) .and().body(Matchers.containsString("Permission Resource Tenant")); - ; + } + + @Test + public void testUserHasSuperUserRoleWebTenant() throws Exception { + testWebAppTenantAllowed("alice"); + testWebAppTenantForbidden("admin"); + testWebAppTenantForbidden("jdoe"); + } + + private void testWebAppTenantAllowed(String user) throws Exception { + try (final WebClient webClient = createWebClient()) { + HtmlPage page = webClient.getPage("http://localhost:8081/api-permission-webapp"); + + assertEquals("Sign in to quarkus", page.getTitleText()); + + HtmlForm loginForm = page.getForms().get(0); + + loginForm.getInputByName("username").setValueAttribute(user); + loginForm.getInputByName("password").setValueAttribute(user); + WebResponse response = loginForm.getInputByName("login").click().getWebResponse(); + assertEquals(200, response.getStatusCode()); + assertTrue(response.getContentAsString().contains("Permission Resource WebApp")); + webClient.getCookieManager().clearCookies(); + } + } + + private void testWebAppTenantForbidden(String user) throws Exception { + try (final WebClient webClient = createWebClient()) { + HtmlPage page = webClient.getPage("http://localhost:8081/api-permission-webapp"); + + assertEquals("Sign in to quarkus", page.getTitleText()); + + HtmlForm loginForm = page.getForms().get(0); + + loginForm.getInputByName("username").setValueAttribute(user); + loginForm.getInputByName("password").setValueAttribute(user); + try { + loginForm.getInputByName("login").click(); + fail("403 status error is expected"); + } catch (FailingHttpStatusCodeException ex) { + assertEquals(403, ex.getStatusCode()); + } + webClient.getCookieManager().clearCookies(); + } + } + + private WebClient createWebClient() { + WebClient webClient = new WebClient(); + webClient.setCssErrorHandler(new SilentCssErrorHandler()); + return webClient; } @Test From ac5ea4e82ba43d4b5313a8d4a84fe0cfd2b4408b Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Tue, 18 May 2021 13:27:03 +0200 Subject: [PATCH 0125/2077] Improve BytecodeRecorderImpl error message When getter type and setter type do not match, provide a better error message with as much information as possible. --- .../recording/BytecodeRecorderImpl.java | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java b/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java index 6d2107a8c2978..713313a520397 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java @@ -1311,26 +1311,33 @@ public void prepare(MethodContext context) { continue; } Class propertyType = i.getPropertyType(); - if (ctorParamIndex == null - && i.getReadMethod().getReturnType() != i.getWriteMethod().getParameterTypes()[0]) { - if (relaxedValidation) { - //this is a weird situation where the reader and writer are different types - //we iterate and try and find a valid setter method for the type we have - //OpenAPI does some weird stuff like this - - for (Method m : param.getClass().getMethods()) { - if (m.getName().equals(i.getWriteMethod().getName())) { - if (m.getParameterTypes().length > 0 - && m.getParameterTypes()[0].isAssignableFrom(param.getClass())) { - propertyType = m.getParameterTypes()[0]; - break; + if (ctorParamIndex == null) { + Class getterReturnType = i.getReadMethod().getReturnType(); + Class setterParameterType = i.getWriteMethod().getParameterTypes()[0]; + if (getterReturnType != setterParameterType) { + if (relaxedValidation) { + //this is a weird situation where the reader and writer are different types + //we iterate and try and find a valid setter method for the type we have + //OpenAPI does some weird stuff like this + + for (Method m : param.getClass().getMethods()) { + if (m.getName().equals(i.getWriteMethod().getName())) { + if (m.getParameterTypes().length > 0 + && m.getParameterTypes()[0].isAssignableFrom(param.getClass())) { + propertyType = m.getParameterTypes()[0]; + break; + } } - } + } + } else { + throw new RuntimeException("Cannot serialise field '" + i.getName() + "' on object '" + param + + "' of type '" + param.getClass().getName() + + "' as getter and setter are of different types. Getter type is '" + + getterReturnType.getName() + "' while setter type is '" + + setterParameterType.getName() + + "'."); } - } else { - throw new RuntimeException("Cannot serialise field " + i.getName() + " on object " + param - + " as setter and getters were different types"); } } DeferredParameter val = loadObjectInstance(propertyValue, existing, From 3464e10bd73aeace0467fea59822faf63ec01a06 Mon Sep 17 00:00:00 2001 From: Michael Simons Date: Mon, 17 May 2021 11:12:09 +0200 Subject: [PATCH 0126/2077] Add a guide howto deploy quarkus to heroku. --- .../main/asciidoc/deploying-to-heroku.adoc | 224 ++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100644 docs/src/main/asciidoc/deploying-to-heroku.adoc diff --git a/docs/src/main/asciidoc/deploying-to-heroku.adoc b/docs/src/main/asciidoc/deploying-to-heroku.adoc new file mode 100644 index 0000000000000..0e82542fc5787 --- /dev/null +++ b/docs/src/main/asciidoc/deploying-to-heroku.adoc @@ -0,0 +1,224 @@ +//// +This guide is maintained in the main Quarkus repository +and pull requests should be submitted there: +https://github.com/quarkusio/quarkus/tree/master/docs/src/main/asciidoc +//// += Quarkus - Deploying to Heroku +include::./attributes.adoc[] + +In this guide you will learn how to deploy a Quarkus based web application as a web-dyno to Heroku. + +This guide covers: + +* Update Quarkus HTTP Port +* Install the Heroku CLI +* Deploy the application to Heroku +* Deploy the application as Docker image to Heroku +* Deploy the native application as Docker image to Heroku + +== Prerequisites + +For this guide you need: + +* Roughly 1 hour for all modalities +* JDK 11 +* Apache Maven {maven-version} +* https://www.heroku.com/[A Heroku Account]. Free accounts work. +* https://devcenter.heroku.com/articles/heroku-cli[Heroku CLI installed] + +== Introduction + +Heroku is a platform as a service (PaaS) that enables developers to build, run, and operate applications entirely in the cloud. +It supports several languages like Java, Ruby, Node.js, Scala, Clojure, Python, PHP, and Go. +In addition it offers a container registry that can be used to deploy prebuilt container images. + +Heroku can be used in different ways to run a Quarkus application: + +* As a plain Java program running in a container defined by Heroku's environment +* As a containerized Java program running in a container defined by the Quarkus build process +* As a containerized native program running in a container defined by the Quarkus build process + +All three approaches need to be aware of the port that Heroku assigns to it to handle traffic. +Luckily, there's a dynamic configuration property for it. + +The guide assumes that you have the https://devcenter.heroku.com/articles/heroku-cli[Heroku CLI] installed. + +== Common project setup + +This guide will take as input an application developed in the link:getting-started[Getting Started guide]. + +Make sure you have the getting-started application at hand, or clone the Git repository: `git clone {quickstarts-clone-url}`, +or download an {quickstarts-archive-url}[archive]. The solution is located in the `getting-started` directory. + +Or, just generate a fresh project: + +[source,bash,subs=attributes+] +---- +mvn io.quarkus:quarkus-maven-plugin:{quarkus-version}:create \ + -DprojectGroupId=org.acme \ + -DprojectArtifactId=code-with-quarkus-on-heroku \ + -DclassName="org.acme.getting.started.GreetingResource" \ + -Dpath="/hello" +cd code-with-quarkus-on-heroku +git init && git add . && git commit -am "Create initial project." +---- + +Heroku can react on changes in your repository, run CI and redeploy your application when your code changes. +Therefore we start with a valid repository already. + +Also, make sure your Heroku CLI is working: + +[source,bash] +---- +heroku --version +heroku login +---- + +== Prepare the Quarkus HTTP Port + +Heroku picks a random port and assigns it to the container that is eventually running your Quarkus application. +That port is available as an environment variable under `$PORT`. +The easiest way to make Quarkus in all deployment scenarios aware of it is using the following configuration: + +[source,properties] +---- +quarkus.http.port=${PORT:8080} +---- + +This reads as: "Listen on `$PORT` if this is a defined variable, otherwise listen on 8080 as usual." +Run the following to add this to your `application.properties`: + +[source,bash] +---- +echo "quarkus.http.port=\${PORT:8080}" >> src/main/resources/application.properties +git commit -am "Configure the HTTP Port." +---- + +== Deploy the repository and build on Heroku + +The first variant uses the Quarkus Maven build to create the _quarkus-app_ application structure containing the runnable "fast-jar" as well as all libraries needed +inside Heroku's build infrastructure and then deploying that result, the other one uses a local build process to create an optimized container. + +Two additional files are needed in your application's root directory: + +* `system.properties` to configure the Java version +* `Procfile` to configure how Heroku starts your application + +Quarkus needs JDK 11, so we specify that first: + +[source,bash] +---- +echo "java.runtime.version=11" >> system.properties +git add system.properties +git commit -am "Configure the Java version for Heroku." +---- + +We will deploy a web application so we need to configure the type `web` in the Heroku `Procfile` like this: + +[source,bash] +---- +echo "web: java \$JAVA_OPTS -jar target/quarkus-app/quarkus-run.jar" >> Procfile +git add Procfile +git commit -am "Add a Procfile." +---- + +Your application should already be runnable via `heroku local web`. + +Let's create an application in your account and deploy that repository to it: + +[source,bash] +---- +heroku create +git push heroku master +heroku open +---- + +The application will have a generated name and the terminal should output that. `heroku open` opens your default browser to access your new application. + +To access the REST endpoint via curl, run: + +[source,bash] +---- +APP_NAME=`heroku info | grep "=== .*" |sed "s/=== //"` +curl $APP_NAME.herokuapp.com/hello +---- + +Of course, you can use the Heroku CLI to connect this repo to your GitHub account, too, but this is out of scope for this guide. + +== Deploy as container + +The advantage of pushing a whole container is that we are in complete control over its content and maybe even choose to deploy a container with a native executable running on GraalVM. + +First, login to Heroku's container registry: + +[source,bash] +----- +heroku container:login +----- + +We need to add an extension to our project to build container images via the Quarkus Maven plugin: + +[source,bash] +---- +mvn quarkus:add-extension -Dextensions="container-image-docker" +git add pom.xml +git commit -am "Add container-image-docker extension." +---- + +The image we are going to build needs to be named accordingly to work with Heroku's registry and deployment. +We get the generated name via `heroku info` and pass it on to the (local) build: + +[source,bash] +---- +APP_NAME=`heroku info | grep "=== .*" |sed "s/=== //"` +mvn clean package\ + -Dquarkus.container-image.build=true\ + -Dquarkus.container-image.group=registry.heroku.com/$APP_NAME\ + -Dquarkus.container-image.name=web\ + -Dquarkus.container-image.tag=latest +---- + +With Docker installed, you can now push the image and release it: + +[source,bash] +---- +docker push registry.heroku.com/$APP_NAME/web +heroku container:release web --app $APP_NAME +---- + +You can and should check the logs to see if your application is now indeed running from the container: + +[source,bash] +---- +heroku logs --app $APP_NAME --tail +---- + +The initial push is rather big, as all layers of the image need to be transferred. +The following pushes will be smaller. + +The biggest advantage we take when deploying our app as a container is to deploy a container with the natively compiled application. +Why? Because Heroku will stop or sleep the application when there's no incoming traffic. +A native application will wake up much faster from its sleep. + +The process is pretty much the same. +We opt in to compiling a native image inside a local container, so that we don't have to deal with installing GraalVM locally: + +[source,bash] +---- +APP_NAME=`heroku info | grep "=== .*" |sed "s/=== //"` +mvn clean package\ + -Dquarkus.container-image.build=true\ + -Dquarkus.container-image.group=registry.heroku.com/$APP_NAME\ + -Dquarkus.container-image.name=web\ + -Dquarkus.container-image.tag=latest\ + -Pnative\ + -Dquarkus.native.container-build=true +---- + +After that, push and release again: + +[source,bash] +---- +docker push registry.heroku.com/$APP_NAME/web +heroku container:release web --app $APP_NAME +---- From 066967e8b422c5fde9bcbabf6d26cb34af724dbe Mon Sep 17 00:00:00 2001 From: Alexey Loubyansky Date: Tue, 18 May 2021 16:29:02 +0200 Subject: [PATCH 0127/2077] DevTools glogal registry client enabling system property and env var --- .../gradle/tasks/QuarkusPlatformTask.java | 8 ++------ .../io/quarkus/maven/CreateProjectMojo.java | 5 +---- .../quarkus/maven/QuarkusProjectMojoBase.java | 6 ++---- .../devtools/project/QuarkusProjectHelper.java | 17 +++++++++++++++-- .../buildfile/MavenProjectBuildFile.java | 4 +++- .../testing/RegistryClientTestHelper.java | 2 ++ 6 files changed, 25 insertions(+), 17 deletions(-) diff --git a/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusPlatformTask.java b/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusPlatformTask.java index 9401798248ea2..b3be14364b38d 100644 --- a/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusPlatformTask.java +++ b/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusPlatformTask.java @@ -32,18 +32,14 @@ public abstract class QuarkusPlatformTask extends QuarkusTask { - private static boolean isEnableRegistryClient() { - final String value = System.getProperty("enableRegistryClient"); - return value == null ? System.getProperties().containsKey("enableRegistryClient") : Boolean.parseBoolean(value); - } - QuarkusPlatformTask(String description) { super(description); } private ExtensionCatalog extensionsCatalog(boolean limitExtensionsToImportedPlatforms, MessageWriter log) { final List platforms = importedPlatforms(); - final ExtensionCatalogResolver catalogResolver = isEnableRegistryClient() ? QuarkusProjectHelper.getCatalogResolver(log) + final ExtensionCatalogResolver catalogResolver = QuarkusProjectHelper.isRegistryClientEnabled() + ? QuarkusProjectHelper.getCatalogResolver(log) : ExtensionCatalogResolver.empty(); if (catalogResolver.hasRegistries()) { try { diff --git a/devtools/maven/src/main/java/io/quarkus/maven/CreateProjectMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/CreateProjectMojo.java index 444af3f2875d0..af94c3c574f0c 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/CreateProjectMojo.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/CreateProjectMojo.java @@ -184,9 +184,6 @@ public class CreateProjectMojo extends AbstractMojo { @Component RemoteRepositoryManager remoteRepoManager; - @Parameter(property = "enableRegistryClient") - private boolean enableRegistryClient; - @Parameter(property = "appConfig") private String appConfig; @@ -214,7 +211,7 @@ public void execute() throws MojoExecutionException { throw new MojoExecutionException("Failed to initialize Maven artifact resolver", e); } final MojoMessageWriter log = new MojoMessageWriter(getLog()); - final ExtensionCatalogResolver catalogResolver = enableRegistryClient + final ExtensionCatalogResolver catalogResolver = QuarkusProjectHelper.isRegistryClientEnabled() ? QuarkusProjectHelper.getCatalogResolver(mvn, log) : ExtensionCatalogResolver.empty(); diff --git a/devtools/maven/src/main/java/io/quarkus/maven/QuarkusProjectMojoBase.java b/devtools/maven/src/main/java/io/quarkus/maven/QuarkusProjectMojoBase.java index 167869ed512b8..ba3d3c82f3ad9 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/QuarkusProjectMojoBase.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/QuarkusProjectMojoBase.java @@ -67,9 +67,6 @@ public abstract class QuarkusProjectMojoBase extends AbstractMojo { @Component RemoteRepositoryManager remoteRepositoryManager; - @Parameter(property = "enableRegistryClient") - private boolean enableRegistryClient; - private List importedPlatforms; private Artifact projectArtifact; @@ -114,7 +111,8 @@ protected Path baseDir() { } private ExtensionCatalog resolveExtensionsCatalog() throws MojoExecutionException { - final ExtensionCatalogResolver catalogResolver = enableRegistryClient ? getExtensionCatalogResolver() + final ExtensionCatalogResolver catalogResolver = QuarkusProjectHelper.isRegistryClientEnabled() + ? getExtensionCatalogResolver() : ExtensionCatalogResolver.empty(); if (catalogResolver.hasRegistries()) { try { diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/QuarkusProjectHelper.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/QuarkusProjectHelper.java index e0bb7bd65430c..244e6a60540ac 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/QuarkusProjectHelper.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/QuarkusProjectHelper.java @@ -21,6 +21,19 @@ public class QuarkusProjectHelper { private static MavenArtifactResolver artifactResolver; private static ExtensionCatalogResolver catalogResolver; + private static final boolean registryClientEnabled; + static { + String value = System.getProperty("quarkusRegistryClient"); + if (value == null) { + value = System.getenv("QUARKUS_REGISTRY_CLIENT"); + } + registryClientEnabled = Boolean.parseBoolean(value); + } + + public static boolean isRegistryClientEnabled() { + return registryClientEnabled; + } + public static QuarkusProject getProject(Path projectDir) { BuildTool buildTool = QuarkusProject.resolveExistingProjectBuildTool(projectDir); if (buildTool == null) { @@ -50,9 +63,9 @@ public static QuarkusProject getProject(Path projectDir, BuildTool buildTool, St @Deprecated public static ExtensionCatalog getExtensionCatalog(String quarkusVersion) { // TODO remove this method once the default registry becomes available - final ExtensionCatalogResolver catalogResolver = getCatalogResolver(); try { - return catalogResolver.hasRegistries() ? catalogResolver.resolveExtensionCatalog(quarkusVersion) + return registryClientEnabled && getCatalogResolver().hasRegistries() + ? getCatalogResolver().resolveExtensionCatalog(quarkusVersion) : ToolsUtils.resolvePlatformDescriptorDirectly(null, null, quarkusVersion, artifactResolver(), messageWriter()); } catch (Exception e) { diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/MavenProjectBuildFile.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/MavenProjectBuildFile.java index 66383ce637f21..cc3d34f4c612a 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/MavenProjectBuildFile.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/MavenProjectBuildFile.java @@ -81,7 +81,9 @@ public static QuarkusProject getProject(Artifact projectPom, Model projectModel, } final ExtensionCatalog extensionCatalog; - final ExtensionCatalogResolver catalogResolver = QuarkusProjectHelper.getCatalogResolver(mvnResolver, log); + final ExtensionCatalogResolver catalogResolver = QuarkusProjectHelper.isRegistryClientEnabled() + ? QuarkusProjectHelper.getCatalogResolver(mvnResolver, log) + : ExtensionCatalogResolver.empty(); if (catalogResolver.hasRegistries()) { try { extensionCatalog = catalogResolver.resolveExtensionCatalog(quarkusVersion); diff --git a/independent-projects/tools/devtools-testing/src/main/java/io/quarkus/devtools/testing/RegistryClientTestHelper.java b/independent-projects/tools/devtools-testing/src/main/java/io/quarkus/devtools/testing/RegistryClientTestHelper.java index d291483fa6e27..a339ed45d0da3 100644 --- a/independent-projects/tools/devtools-testing/src/main/java/io/quarkus/devtools/testing/RegistryClientTestHelper.java +++ b/independent-projects/tools/devtools-testing/src/main/java/io/quarkus/devtools/testing/RegistryClientTestHelper.java @@ -43,6 +43,7 @@ public static void enableRegistryClientTestConfig(Path outputDir, Properties pro properties.setProperty("io.quarkus.maven.secondary-local-repo", registryRepoPath.toString()); properties.setProperty(RegistriesConfigLocator.CONFIG_FILE_PATH_PROPERTY, toolsConfigPath.toString()); + properties.setProperty("quarkusRegistryClient", "true"); } private static void generatePlatformCatalog(final Path groupIdDir) { @@ -134,5 +135,6 @@ public static void disableRegistryClientTestConfig() { public static void disableRegistryClientTestConfig(Properties properties) { properties.remove("io.quarkus.maven.secondary-local-repo"); properties.remove(RegistriesConfigLocator.CONFIG_FILE_PATH_PROPERTY); + properties.remove("quarkusRegistryClient"); } } From 3533c8d107fbcf1fdeb4a7a25a7aee25e8ea8d38 Mon Sep 17 00:00:00 2001 From: Andy Damevin Date: Tue, 18 May 2021 16:45:42 +0200 Subject: [PATCH 0128/2077] Improve continuous testing status message episode 2 --- .../dev/testing/TestConsoleHandler.java | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java index b73a61cf7e9df..4d92f5545ecbe 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java @@ -152,19 +152,21 @@ public void testComplete(TestResult result) { @Override public void runComplete(TestRunResults results) { - String resultString = String.format( - "%d/%d tests are failing (%d/%d from the last run). %d tests are skipped. Run %d took %dms.", - results.getFailedCount(), results.getTotalCount(), results.getCurrentFailedCount(), - results.getCurrentTotalCount(), results.getSkippedCount(), - results.getId(), results.getTotalTime()); firstRun = false; if (results.getCurrentFailing().isEmpty()) { - lastStatus = "\u001B[32m" + resultString + "\u001b[0m"; + lastStatus = String.format( + "\u001B[32mAll %d tests are passing (%d skipped), %d tests were run in %dms.\u001b[0m", + results.getPassedCount(), + results.getSkippedCount(), + results.getCurrentTotalCount(), results.getTotalTime()); + log.info( + ">>>>>>>>>>>>>>>>>>>> \u001B[32m TEST #" + results.getId() + + " PASSED\u001b[0m <<<<<<<<<<<<<<<<<<<"); } else { //TODO: this should not use the logger, it should print a nicer status log.error( - "==================== \u001B[91m" + results.getCurrentFailedCount() - + " TESTS FAILED\u001b[0m ===================="); + "==================== \u001B[91m TEST REPORT #" + results.getId() + + "\u001b[0m ===================="); for (Map.Entry classEntry : results.getCurrentFailing().entrySet()) { for (TestResult test : classEntry.getValue().getFailing()) { log.error( @@ -173,8 +175,12 @@ public void runComplete(TestRunResults results) { } } log.error( - "==================== \u001B[91mEND TEST REPORT\u001b[0m ===================="); - lastStatus = "\u001B[91m" + resultString + "\u001b[0m"; + ">>>>>>>>>>>>>>>>>>>> \u001B[91m " + results.getCurrentFailedCount() + + " TESTS FAILED\u001b[0m <<<<<<<<<<<<<<<<<<<<"); + lastStatus = String.format( + "\u001B[91m%d tests failed (%d passing, %d skipped), %d tests were run in %dms.\u001b[0m", + results.getCurrentFailedCount(), results.getPassedCount(), results.getSkippedCount(), + results.getCurrentTotalCount(), results.getTotalTime()); } //this will re-print when using the basic console promptHandler.setPrompt(RUNNING_PROMPT); From bb06c3ab28820b0bb35fb54c305e568efd22ca1c Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 18 May 2021 17:34:44 +0300 Subject: [PATCH 0129/2077] When container image credentials present, use only those This is done in order to make Jib not fail if there are invalid credentials in the docker config file Relates to: #10683 --- .../quarkus/container/image/jib/deployment/JibProcessor.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 f7c960840ffc9..7a61648d0afb6 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 @@ -220,10 +220,11 @@ private RegistryImage toRegistryImage(ImageReference imageReference, Optional Date: Tue, 18 May 2021 17:25:54 +0200 Subject: [PATCH 0130/2077] Add report number when tests passed --- .../deployment/dev/testing/TestConsoleHandler.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java index 4d92f5545ecbe..03471acad0de1 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConsoleHandler.java @@ -160,12 +160,15 @@ public void runComplete(TestRunResults results) { results.getSkippedCount(), results.getCurrentTotalCount(), results.getTotalTime()); log.info( - ">>>>>>>>>>>>>>>>>>>> \u001B[32m TEST #" + results.getId() - + " PASSED\u001b[0m <<<<<<<<<<<<<<<<<<<"); + "====================\u001B[32m TEST REPORT #" + results.getId() + + "\u001b[0m ===================="); + log.info( + ">>>>>>>>>>>>>>>>>>>>\u001B[32m " + results.getCurrentPassedCount() + + " TESTS PASSED\u001b[0m <<<<<<<<<<<<<<<<<<<<"); } else { //TODO: this should not use the logger, it should print a nicer status log.error( - "==================== \u001B[91m TEST REPORT #" + results.getId() + "====================\u001B[91m TEST REPORT #" + results.getId() + "\u001b[0m ===================="); for (Map.Entry classEntry : results.getCurrentFailing().entrySet()) { for (TestResult test : classEntry.getValue().getFailing()) { @@ -175,7 +178,7 @@ public void runComplete(TestRunResults results) { } } log.error( - ">>>>>>>>>>>>>>>>>>>> \u001B[91m " + results.getCurrentFailedCount() + ">>>>>>>>>>>>>>>>>>>>\u001B[91m " + results.getCurrentFailedCount() + " TESTS FAILED\u001b[0m <<<<<<<<<<<<<<<<<<<<"); lastStatus = String.format( "\u001B[91m%d tests failed (%d passing, %d skipped), %d tests were run in %dms.\u001b[0m", From 413c2b6643a505086b289d25263a95eae89d2591 Mon Sep 17 00:00:00 2001 From: Stephane Epardaud Date: Fri, 4 Dec 2020 18:27:32 +0100 Subject: [PATCH 0131/2077] New APT processor to support validation of annotated methods --- bom/application/pom.xml | 6 +++ docs/src/main/asciidoc/resteasy-reactive.adoc | 41 ++++++++++++++++++ .../deployment/pom.xml | 18 ++++++++ .../quarkus-resteasy-reactive/runtime/pom.xml | 4 ++ .../ServerExceptionMapperOverride.java | 37 ++++++++++++++++ .../runtime/ServerRequestFilterOverride.java | 43 +++++++++++++++++++ .../runtime/ServerResponseFilterOverride.java | 31 +++++++++++++ ...llrye.safer.annotations.DefinitionOverride | 3 ++ .../resteasy-reactive/pom.xml | 7 +++ .../resteasy-reactive/server/runtime/pom.xml | 4 ++ .../server/ServerExceptionMapper.java | 10 +++++ .../reactive/server/ServerRequestFilter.java | 10 +++++ .../reactive/server/ServerResponseFilter.java | 24 ++++++++++- 13 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ServerExceptionMapperOverride.java create mode 100644 extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ServerRequestFilterOverride.java create mode 100644 extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ServerResponseFilterOverride.java create mode 100644 extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/resources/META-INF/services/io.smallrye.safer.annotations.DefinitionOverride diff --git a/bom/application/pom.xml b/bom/application/pom.xml index bb15a0477c8aa..110eb07b27286 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -54,6 +54,7 @@ 1.0.13 2.5.1 3.2.0 + 1.0.3 1.2.1 1.3.5 3.0.3 @@ -4047,6 +4048,11 @@ jboss-transaction-spi ${jboss-transaction-spi.version} + + io.smallrye + smallrye-safer-annotations + ${smallrye-safer-annotations.version} + io.quarkus.arc arc-processor diff --git a/docs/src/main/asciidoc/resteasy-reactive.adoc b/docs/src/main/asciidoc/resteasy-reactive.adoc index 849f6c7469aab..24fedbdda1cfa 100644 --- a/docs/src/main/asciidoc/resteasy-reactive.adoc +++ b/docs/src/main/asciidoc/resteasy-reactive.adoc @@ -915,6 +915,47 @@ It is important to note that this customization is only performed for the serial Here are some more advanced topics that you may not need to know about initially, but could prove useful for more complex use cases. +=== Better error messages in your source files + +In order to get better type safety and error messages directly in your IDE, RESTEasy Reactive uses the +https://github.com/smallrye/smallrye-safer-annotations[SmallRye Safer Annotations] compiler plugin, which +you will get automatically as soon as you import the `quarkus-resteasy-reactive` extension. + +If you are using the Eclipse IDE, you may want to install the https://marketplace.eclipse.org/content/m2e-apt[M2E APT] +plugin and enable it by adding this property to your `pom.xml`: + +[source,xml] +---- + + jdt_apt + +---- + +Note that if you configure any compiler plugin manually via `annotationProcessorPaths` you +will need to list `smallrye-safer-annotations` explicitely as it will not be picked up +from the transitive classpath anymore: + +[source,xml] +---- + + + + maven-compiler-plugin + ${compiler-plugin.version} + + + + io.smallrye + smallrye-safer-annotations + 1.0.2 + + + + + + +---- + === Execution model, blocking, non-blocking [[execution-model]] diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/pom.xml b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/pom.xml index a4a896e2a2f50..a2e232af8a04d 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/pom.xml +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/pom.xml @@ -111,6 +111,24 @@ maven-compiler-plugin + + + + test-compile + + testCompile + + false + + + + io.smallrye + smallrye-safer-annotations + + + + + diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/pom.xml b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/pom.xml index 1c2455a13f238..bedb3ef8122d0 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/pom.xml +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/pom.xml @@ -48,6 +48,10 @@ io.quarkus quarkus-jsonp + + io.smallrye + smallrye-safer-annotations + diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ServerExceptionMapperOverride.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ServerExceptionMapperOverride.java new file mode 100644 index 0000000000000..64aaede2c0c10 --- /dev/null +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ServerExceptionMapperOverride.java @@ -0,0 +1,37 @@ +package io.quarkus.resteasy.reactive.server.runtime; + +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ResourceInfo; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Request; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.jboss.resteasy.reactive.server.ServerExceptionMapper; +import org.jboss.resteasy.reactive.server.SimpleResourceInfo; + +import io.smallrye.mutiny.Uni; +import io.smallrye.safer.annotations.DefinitionOverride; +import io.smallrye.safer.annotations.OverrideTarget; +import io.smallrye.safer.annotations.TargetMethod; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.ext.web.RoutingContext; + +/** + * Adds the following allowed parameters to the Safer-Annotations type checking + * - RoutingContext + * - HttpServerRequest + */ +@OverrideTarget(ServerExceptionMapper.class) +@TargetMethod(returnTypes = { Response.class, UniResponse.class }, parameterTypes = { + ContainerRequestContext.class, UriInfo.class, HttpHeaders.class, Request.class, + ResourceInfo.class, SimpleResourceInfo.class, RoutingContext.class, ThrowableSubtype.class, HttpServerRequest.class }) +public class ServerExceptionMapperOverride implements DefinitionOverride { + +} + +class UniResponse extends TargetMethod.GenericType> { +} + +class ThrowableSubtype extends TargetMethod.Subtype { +} \ No newline at end of file diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ServerRequestFilterOverride.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ServerRequestFilterOverride.java new file mode 100644 index 0000000000000..9bc4f2be6bd06 --- /dev/null +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ServerRequestFilterOverride.java @@ -0,0 +1,43 @@ +package io.quarkus.resteasy.reactive.server.runtime; + +import java.util.Optional; + +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ResourceInfo; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Request; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.jboss.resteasy.reactive.server.ServerRequestFilter; +import org.jboss.resteasy.reactive.server.SimpleResourceInfo; +import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveContainerRequestContext; + +import io.smallrye.mutiny.Uni; +import io.smallrye.safer.annotations.DefinitionOverride; +import io.smallrye.safer.annotations.OverrideTarget; +import io.smallrye.safer.annotations.TargetMethod; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.ext.web.RoutingContext; + +/** + * Adds the following allowed parameters to the Safer-Annotations type checking + * - RoutingContext + * - HttpServerRequest + */ +@OverrideTarget(ServerRequestFilter.class) +@TargetMethod(returnTypes = { void.class, Response.class, UniResponse.class, UniVoid.class, + OptionalResponse.class }, parameterTypes = { + ContainerRequestContext.class, UriInfo.class, HttpHeaders.class, Request.class, + ResourceInfo.class, SimpleResourceInfo.class, ResteasyReactiveContainerRequestContext.class, + RoutingContext.class, + HttpServerRequest.class }) +public class ServerRequestFilterOverride implements DefinitionOverride { + +} + +class UniVoid extends TargetMethod.GenericType> { +} + +class OptionalResponse extends TargetMethod.GenericType> { +} diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ServerResponseFilterOverride.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ServerResponseFilterOverride.java new file mode 100644 index 0000000000000..32cf0ae65eb96 --- /dev/null +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ServerResponseFilterOverride.java @@ -0,0 +1,31 @@ +package io.quarkus.resteasy.reactive.server.runtime; + +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerResponseContext; +import javax.ws.rs.container.ResourceInfo; + +import org.jboss.resteasy.reactive.server.ServerResponseFilter; +import org.jboss.resteasy.reactive.server.SimpleResourceInfo; +import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveContainerRequestContext; + +import io.smallrye.safer.annotations.DefinitionOverride; +import io.smallrye.safer.annotations.OverrideTarget; +import io.smallrye.safer.annotations.TargetMethod; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.ext.web.RoutingContext; + +/** + * Adds the following allowed parameters to the Safer-Annotations type checking + * - RoutingContext + * - HttpServerRequest + */ +@OverrideTarget(ServerResponseFilter.class) +@TargetMethod(returnTypes = { void.class, UniVoid.class }, parameterTypes = { + ContainerRequestContext.class, + ContainerResponseContext.class, + ResteasyReactiveContainerRequestContext.class, + ResourceInfo.class, SimpleResourceInfo.class, Throwable.class, RoutingContext.class, + HttpServerRequest.class }) +public class ServerResponseFilterOverride implements DefinitionOverride { + +} diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/resources/META-INF/services/io.smallrye.safer.annotations.DefinitionOverride b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/resources/META-INF/services/io.smallrye.safer.annotations.DefinitionOverride new file mode 100644 index 0000000000000..c40d327199e91 --- /dev/null +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/resources/META-INF/services/io.smallrye.safer.annotations.DefinitionOverride @@ -0,0 +1,3 @@ +io.quarkus.resteasy.reactive.server.runtime.ServerExceptionMapperOverride +io.quarkus.resteasy.reactive.server.runtime.ServerRequestFilterOverride +io.quarkus.resteasy.reactive.server.runtime.ServerResponseFilterOverride diff --git a/independent-projects/resteasy-reactive/pom.xml b/independent-projects/resteasy-reactive/pom.xml index eae63fa065a3c..4da896d29c157 100644 --- a/independent-projects/resteasy-reactive/pom.xml +++ b/independent-projects/resteasy-reactive/pom.xml @@ -52,6 +52,7 @@ 1.1.6 0.17.0 1.6.0 + 1.0.3 4.0.3 4.3.3 1.0.0.Final @@ -164,6 +165,12 @@ pom + + io.smallrye + smallrye-safer-annotations + ${smallrye-safer-annotations.version} + + org.junit diff --git a/independent-projects/resteasy-reactive/server/runtime/pom.xml b/independent-projects/resteasy-reactive/server/runtime/pom.xml index 0dc1ab737ce27..1f4dc21c587d0 100644 --- a/independent-projects/resteasy-reactive/server/runtime/pom.xml +++ b/independent-projects/resteasy-reactive/server/runtime/pom.xml @@ -15,6 +15,10 @@ + + io.smallrye + smallrye-safer-annotations + io.quarkus.resteasy.reactive resteasy-reactive-common diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/ServerExceptionMapper.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/ServerExceptionMapper.java index 1b946b780e941..9cae364d29168 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/ServerExceptionMapper.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/ServerExceptionMapper.java @@ -1,5 +1,6 @@ package org.jboss.resteasy.reactive.server; +import io.smallrye.safer.annotations.TargetMethod; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -9,6 +10,7 @@ import javax.ws.rs.container.ResourceInfo; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Request; +import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; /** @@ -34,6 +36,8 @@ *

  • {@link Request} *
  • {@link ResourceInfo} *
  • {@link SimpleResourceInfo} + *
  • io.vertx.ext.web.RoutingContext + *
  • io.vertx.core.http.HttpServerRequest * * * When {@code value} is not set, then the handled Exception type is deduced by the Exception type used in the method parameters @@ -43,6 +47,9 @@ */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) +@TargetMethod(returnTypes = { Response.class, UniResponse.class }, parameterTypes = { + ContainerRequestContext.class, UriInfo.class, HttpHeaders.class, Request.class, + ResourceInfo.class, SimpleResourceInfo.class, ThrowableSubtype.class }) public @interface ServerExceptionMapper { Class[] value() default {}; @@ -52,3 +59,6 @@ */ int priority() default Priorities.USER; } + +class ThrowableSubtype extends TargetMethod.Subtype { +} \ No newline at end of file diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/ServerRequestFilter.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/ServerRequestFilter.java index 7d9b5af2732b7..943015dd0ed95 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/ServerRequestFilter.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/ServerRequestFilter.java @@ -1,6 +1,7 @@ package org.jboss.resteasy.reactive.server; import io.smallrye.common.annotation.Blocking; +import io.smallrye.safer.annotations.TargetMethod; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -11,7 +12,9 @@ import javax.ws.rs.container.ResourceInfo; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Request; +import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; +import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveContainerRequestContext; /** * When used on a method, then an implementation of {@link javax.ws.rs.container.ContainerRequestFilter} is generated @@ -48,6 +51,9 @@ *
  • {@link Request} *
  • {@link ResourceInfo} *
  • {@link SimpleResourceInfo} + *
  • {@link ResteasyReactiveContainerRequestContext} + *
  • io.vertx.ext.web.RoutingContext + *
  • io.vertx.core.http.HttpServerRequest * * * The return type of the method must be either be of type {@code void}, {@code Response}, {@code Optional}, @@ -74,6 +80,10 @@ */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) +@TargetMethod(returnTypes = { void.class, Response.class, UniResponse.class, UniVoid.class, + OptionalResponse.class }, parameterTypes = { + ContainerRequestContext.class, UriInfo.class, HttpHeaders.class, Request.class, + ResourceInfo.class, SimpleResourceInfo.class, ResteasyReactiveContainerRequestContext.class }) public @interface ServerRequestFilter { /** diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/ServerResponseFilter.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/ServerResponseFilter.java index daf7fa44c1e1c..65b6899b66ef0 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/ServerResponseFilter.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/ServerResponseFilter.java @@ -1,13 +1,18 @@ package org.jboss.resteasy.reactive.server; +import io.smallrye.mutiny.Uni; +import io.smallrye.safer.annotations.TargetMethod; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.util.Optional; import javax.ws.rs.Priorities; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerResponseContext; import javax.ws.rs.container.ResourceInfo; +import javax.ws.rs.core.Response; +import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveContainerRequestContext; /** * When used on a method, then an implementation of {@link javax.ws.rs.container.ContainerResponseContext} is generated @@ -43,9 +48,12 @@ *
  • {@link ResourceInfo} *
  • {@link SimpleResourceInfo} *
  • {@link Throwable} - The thrown exception - or {@code null} if no exception was thrown + *
  • {@link ResteasyReactiveContainerRequestContext} + *
  • io.vertx.ext.web.RoutingContext + *
  • io.vertx.core.http.HttpServerRequest * * - * The return type of the method must be either be of type {@code void} or {@code Uni}. + * The return type of the method must either be of type {@code void} or {@code Uni}. *