From 8b7d549bb6ecbc89dd3536391e3f665bf58fd5e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Tue, 2 Aug 2022 16:32:39 +0200 Subject: [PATCH] Add build-time configuration property quarkus.hibernate-envers.enabled --- ...HibernateEnversAlwaysEnabledProcessor.java | 23 ++++++++++ .../HibernateEnversDisabledProcessor.java | 31 +++++++++++++ .../deployment/HibernateEnversEnabled.java | 24 +++++++++++ .../deployment/HibernateEnversProcessor.java | 18 ++------ ...onfigEnabledFalseAndAuditedEntityTest.java | 43 +++++++++++++++++++ .../HibernateEnversBuildTimeConfig.java | 13 ++++++ .../envers/HibernateEnversRecorder.java | 28 ++++++++++-- 7 files changed, 162 insertions(+), 18 deletions(-) create mode 100644 extensions/hibernate-envers/deployment/src/main/java/io/quarkus/hibernate/envers/deployment/HibernateEnversAlwaysEnabledProcessor.java create mode 100644 extensions/hibernate-envers/deployment/src/main/java/io/quarkus/hibernate/envers/deployment/HibernateEnversDisabledProcessor.java create mode 100644 extensions/hibernate-envers/deployment/src/main/java/io/quarkus/hibernate/envers/deployment/HibernateEnversEnabled.java create mode 100644 extensions/hibernate-envers/deployment/src/test/java/io/quarkus/hibernate/orm/envers/config/ConfigEnabledFalseAndAuditedEntityTest.java diff --git a/extensions/hibernate-envers/deployment/src/main/java/io/quarkus/hibernate/envers/deployment/HibernateEnversAlwaysEnabledProcessor.java b/extensions/hibernate-envers/deployment/src/main/java/io/quarkus/hibernate/envers/deployment/HibernateEnversAlwaysEnabledProcessor.java new file mode 100644 index 0000000000000..f214982eca6e2 --- /dev/null +++ b/extensions/hibernate-envers/deployment/src/main/java/io/quarkus/hibernate/envers/deployment/HibernateEnversAlwaysEnabledProcessor.java @@ -0,0 +1,23 @@ +package io.quarkus.hibernate.envers.deployment; + +import io.quarkus.deployment.Feature; +import io.quarkus.deployment.annotations.BuildProducer; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.builditem.FeatureBuildItem; +import io.quarkus.deployment.logging.LogCleanupFilterBuildItem; + +// Executed even if the extension is disabled, see https://github.com/quarkusio/quarkus/pull/26966/ +public final class HibernateEnversAlwaysEnabledProcessor { + + @BuildStep + FeatureBuildItem feature() { + return new FeatureBuildItem(Feature.HIBERNATE_ENVERS); + } + + @BuildStep + void setupLogFilters(BuildProducer filters) { + filters.produce(new LogCleanupFilterBuildItem("org.hibernate.envers.boot.internal.EnversServiceImpl", + "Envers integration enabled")); + } + +} diff --git a/extensions/hibernate-envers/deployment/src/main/java/io/quarkus/hibernate/envers/deployment/HibernateEnversDisabledProcessor.java b/extensions/hibernate-envers/deployment/src/main/java/io/quarkus/hibernate/envers/deployment/HibernateEnversDisabledProcessor.java new file mode 100644 index 0000000000000..3370dc18367e0 --- /dev/null +++ b/extensions/hibernate-envers/deployment/src/main/java/io/quarkus/hibernate/envers/deployment/HibernateEnversDisabledProcessor.java @@ -0,0 +1,31 @@ +package io.quarkus.hibernate.envers.deployment; + +import java.util.List; + +import io.quarkus.deployment.annotations.BuildProducer; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.annotations.BuildSteps; +import io.quarkus.deployment.annotations.ExecutionTime; +import io.quarkus.deployment.annotations.Record; +import io.quarkus.hibernate.envers.HibernateEnversRecorder; +import io.quarkus.hibernate.orm.deployment.PersistenceUnitDescriptorBuildItem; +import io.quarkus.hibernate.orm.deployment.integration.HibernateOrmIntegrationStaticConfiguredBuildItem; + +@BuildSteps(onlyIfNot = HibernateEnversEnabled.class) +public final class HibernateEnversDisabledProcessor { + + @BuildStep + @Record(ExecutionTime.STATIC_INIT) + public void disableHibernateEnvers(HibernateEnversRecorder recorder, + List persistenceUnitDescriptorBuildItems, + BuildProducer integrationProducer) { + for (PersistenceUnitDescriptorBuildItem puDescriptor : persistenceUnitDescriptorBuildItems) { + integrationProducer.produce( + new HibernateOrmIntegrationStaticConfiguredBuildItem(HibernateEnversProcessor.HIBERNATE_ENVERS, + puDescriptor.getPersistenceUnitName()) + .setInitListener(recorder.createStaticInitInactiveListener()) + // We don't need XML mapping if Envers is disabled + .setXmlMappingRequired(false)); + } + } +} diff --git a/extensions/hibernate-envers/deployment/src/main/java/io/quarkus/hibernate/envers/deployment/HibernateEnversEnabled.java b/extensions/hibernate-envers/deployment/src/main/java/io/quarkus/hibernate/envers/deployment/HibernateEnversEnabled.java new file mode 100644 index 0000000000000..5451c0d2828e3 --- /dev/null +++ b/extensions/hibernate-envers/deployment/src/main/java/io/quarkus/hibernate/envers/deployment/HibernateEnversEnabled.java @@ -0,0 +1,24 @@ +package io.quarkus.hibernate.envers.deployment; + +import java.util.function.BooleanSupplier; + +import io.quarkus.hibernate.envers.HibernateEnversBuildTimeConfig; + +/** + * Supplier that can be used to only run build steps + * if the Hibernate Envers extension is enabled. + */ +public class HibernateEnversEnabled implements BooleanSupplier { + + private final HibernateEnversBuildTimeConfig config; + + HibernateEnversEnabled(HibernateEnversBuildTimeConfig config) { + this.config = config; + } + + @Override + public boolean getAsBoolean() { + return config.enabled; + } + +} diff --git a/extensions/hibernate-envers/deployment/src/main/java/io/quarkus/hibernate/envers/deployment/HibernateEnversProcessor.java b/extensions/hibernate-envers/deployment/src/main/java/io/quarkus/hibernate/envers/deployment/HibernateEnversProcessor.java index b28e13f115f92..26ef398a317e7 100644 --- a/extensions/hibernate-envers/deployment/src/main/java/io/quarkus/hibernate/envers/deployment/HibernateEnversProcessor.java +++ b/extensions/hibernate-envers/deployment/src/main/java/io/quarkus/hibernate/envers/deployment/HibernateEnversProcessor.java @@ -3,28 +3,22 @@ import java.util.Arrays; import java.util.List; -import io.quarkus.deployment.Feature; import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.annotations.BuildSteps; import io.quarkus.deployment.annotations.ExecutionTime; import io.quarkus.deployment.annotations.Record; -import io.quarkus.deployment.builditem.FeatureBuildItem; import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; -import io.quarkus.deployment.logging.LogCleanupFilterBuildItem; import io.quarkus.hibernate.envers.HibernateEnversBuildTimeConfig; import io.quarkus.hibernate.envers.HibernateEnversRecorder; import io.quarkus.hibernate.orm.deployment.AdditionalJpaModelBuildItem; import io.quarkus.hibernate.orm.deployment.PersistenceUnitDescriptorBuildItem; import io.quarkus.hibernate.orm.deployment.integration.HibernateOrmIntegrationStaticConfiguredBuildItem; +@BuildSteps(onlyIf = HibernateEnversEnabled.class) public final class HibernateEnversProcessor { - private static final String HIBERNATE_ENVERS = "Hibernate Envers"; - - @BuildStep - FeatureBuildItem feature() { - return new FeatureBuildItem(Feature.HIBERNATE_ENVERS); - } + static final String HIBERNATE_ENVERS = "Hibernate Envers"; @BuildStep List addJpaModelClasses() { @@ -61,10 +55,4 @@ public void applyConfig(HibernateEnversRecorder recorder, HibernateEnversBuildTi .setXmlMappingRequired(true)); } } - - @BuildStep - void setupLogFilters(BuildProducer filters) { - filters.produce(new LogCleanupFilterBuildItem("org.hibernate.envers.boot.internal.EnversServiceImpl", - "Envers integration enabled")); - } } diff --git a/extensions/hibernate-envers/deployment/src/test/java/io/quarkus/hibernate/orm/envers/config/ConfigEnabledFalseAndAuditedEntityTest.java b/extensions/hibernate-envers/deployment/src/test/java/io/quarkus/hibernate/orm/envers/config/ConfigEnabledFalseAndAuditedEntityTest.java new file mode 100644 index 0000000000000..1dd0e45d9cfc8 --- /dev/null +++ b/extensions/hibernate-envers/deployment/src/test/java/io/quarkus/hibernate/orm/envers/config/ConfigEnabledFalseAndAuditedEntityTest.java @@ -0,0 +1,43 @@ +package io.quarkus.hibernate.orm.envers.config; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import javax.inject.Inject; +import javax.persistence.metamodel.Bindable; + +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.envers.AuditReaderFactory; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.hibernate.orm.envers.MyAuditedEntity; +import io.quarkus.test.QuarkusUnitTest; + +public class ConfigEnabledFalseAndAuditedEntityTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar.addClass(MyAuditedEntity.class)) + .withConfigurationResource("application.properties") + .overrideConfigKey("quarkus.hibernate-envers.enabled", "false"); + + @Inject + SessionFactory sessionFactory; + + @Test + @SuppressWarnings("rawtypes") + public void test() { + assertThat(sessionFactory.getMetamodel().getEntities()) + .extracting(Bindable::getBindableJavaType) + // In particular this should not contain the revision entity + .containsExactly((Class) MyAuditedEntity.class); + + try (Session session = sessionFactory.openSession()) { + assertThatThrownBy(() -> AuditReaderFactory.get(session).isEntityClassAudited(MyAuditedEntity.class)) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("Service is not yet initialized"); + } + } +} diff --git a/extensions/hibernate-envers/runtime/src/main/java/io/quarkus/hibernate/envers/HibernateEnversBuildTimeConfig.java b/extensions/hibernate-envers/runtime/src/main/java/io/quarkus/hibernate/envers/HibernateEnversBuildTimeConfig.java index 1a7ddb61480b5..2fe0589541dab 100644 --- a/extensions/hibernate-envers/runtime/src/main/java/io/quarkus/hibernate/envers/HibernateEnversBuildTimeConfig.java +++ b/extensions/hibernate-envers/runtime/src/main/java/io/quarkus/hibernate/envers/HibernateEnversBuildTimeConfig.java @@ -8,6 +8,19 @@ @ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) public class HibernateEnversBuildTimeConfig { + /** + * Whether Hibernate Envers is enabled during the build. + * + * If Hibernate Envers is disabled during the build, all processing related to Hibernate Envers will be skipped, + * and the audit entities will not be added to the Hibernate ORM metamodel + * nor to the database schema that Hibernate ORM generates, + * but it will not be possible to use Hibernate Envers at runtime. + * + * @asciidoclet + */ + @ConfigItem(defaultValue = "true") + public boolean enabled; + /** * Enable store_data_at_delete feature. * Maps to {@link org.hibernate.envers.configuration.EnversSettings#STORE_DATA_AT_DELETE}. diff --git a/extensions/hibernate-envers/runtime/src/main/java/io/quarkus/hibernate/envers/HibernateEnversRecorder.java b/extensions/hibernate-envers/runtime/src/main/java/io/quarkus/hibernate/envers/HibernateEnversRecorder.java index a1b6a3426d25f..c895a273b6692 100644 --- a/extensions/hibernate-envers/runtime/src/main/java/io/quarkus/hibernate/envers/HibernateEnversRecorder.java +++ b/extensions/hibernate-envers/runtime/src/main/java/io/quarkus/hibernate/envers/HibernateEnversRecorder.java @@ -5,6 +5,7 @@ import org.hibernate.boot.Metadata; import org.hibernate.boot.spi.BootstrapContext; +import org.hibernate.envers.boot.internal.EnversService; import org.hibernate.envers.configuration.EnversSettings; import io.quarkus.hibernate.orm.runtime.integration.HibernateOrmIntegrationStaticInitListener; @@ -14,13 +15,14 @@ public class HibernateEnversRecorder { public HibernateOrmIntegrationStaticInitListener createStaticInitListener(HibernateEnversBuildTimeConfig buildTimeConfig) { - return new HibernateEnversIntegrationListener(buildTimeConfig); + return new HibernateEnversIntegrationStaticInitListener(buildTimeConfig); } - private static final class HibernateEnversIntegrationListener implements HibernateOrmIntegrationStaticInitListener { + private static final class HibernateEnversIntegrationStaticInitListener + implements HibernateOrmIntegrationStaticInitListener { private HibernateEnversBuildTimeConfig buildTimeConfig; - private HibernateEnversIntegrationListener(HibernateEnversBuildTimeConfig buildTimeConfig) { + private HibernateEnversIntegrationStaticInitListener(HibernateEnversBuildTimeConfig buildTimeConfig) { this.buildTimeConfig = buildTimeConfig; } @@ -81,4 +83,24 @@ public void onMetadataInitialized(Metadata metadata, BootstrapContext bootstrapC BiConsumer propertyCollector) { } } + + public HibernateOrmIntegrationStaticInitListener createStaticInitInactiveListener() { + return new HibernateEnversIntegrationStaticInitInactiveListener(); + } + + private static final class HibernateEnversIntegrationStaticInitInactiveListener + implements HibernateOrmIntegrationStaticInitListener { + private HibernateEnversIntegrationStaticInitInactiveListener() { + } + + @Override + public void contributeBootProperties(BiConsumer propertyCollector) { + propertyCollector.accept(EnversService.INTEGRATION_ENABLED, "false"); + } + + @Override + public void onMetadataInitialized(Metadata metadata, BootstrapContext bootstrapContext, + BiConsumer propertyCollector) { + } + } }