Skip to content

Commit

Permalink
Merge pull request #26965 from yrodiere/onlyif-multiple-build-steps
Browse files Browse the repository at this point in the history
Support @buildsteps on buildstep classes to apply conditions to all build steps of that class
  • Loading branch information
yrodiere authored Jul 28, 2022
2 parents 8e41c5c + 9b85e36 commit 80304e4
Show file tree
Hide file tree
Showing 37 changed files with 308 additions and 153 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
import io.quarkus.builder.item.SimpleBuildItem;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.BuildSteps;
import io.quarkus.deployment.annotations.Consume;
import io.quarkus.deployment.annotations.ExecutionTime;
import io.quarkus.deployment.annotations.Overridable;
Expand Down Expand Up @@ -112,12 +113,15 @@
* Utility class to load build steps, runtime recorders, and configuration roots from a given extension class.
*/
public final class ExtensionLoader {

private ExtensionLoader() {
}

private static final Logger loadLog = Logger.getLogger("io.quarkus.deployment");
private static final Logger cfgLog = Logger.getLogger("io.quarkus.configuration");
private static final String CONFIG_ROOTS_LIST = "META-INF/quarkus-config-roots.list";
@SuppressWarnings("unchecked")
private static final Class<? extends BooleanSupplier>[] EMPTY_BOOLEAN_SUPPLIER_CLASS_ARRAY = new Class[0];

@SuppressWarnings("deprecation")
private static boolean isRecorder(AnnotatedElement element) {
Expand Down Expand Up @@ -545,6 +549,13 @@ private static Consumer<BuildChainBuilder> loadStepsFromClass(Class<?> clazz,
}
}

// get class-level configuration, if any
final BuildSteps buildSteps = clazz.getAnnotation(BuildSteps.class);
final Class<? extends BooleanSupplier>[] classOnlyIf = buildSteps == null ? EMPTY_BOOLEAN_SUPPLIER_CLASS_ARRAY
: buildSteps.onlyIf();
final Class<? extends BooleanSupplier>[] classOnlyIfNot = buildSteps == null ? EMPTY_BOOLEAN_SUPPLIER_CLASS_ARRAY
: buildSteps.onlyIfNot();

// now iterate the methods
final List<Method> methods = getMethods(clazz);
final Map<String, List<Method>> nameToMethods = methods.stream().collect(Collectors.groupingBy(m -> m.getName()));
Expand Down Expand Up @@ -581,17 +592,10 @@ private static Consumer<BuildChainBuilder> loadStepsFromClass(Class<?> clazz,
final List<BiFunction<BuildContext, BytecodeRecorderImpl, Object>> methodParamFns;
Consumer<BuildStepBuilder> methodStepConfig = Functions.discardingConsumer();
BooleanSupplier addStep = () -> true;
for (boolean inv : new boolean[] { false, true }) {
Class<? extends BooleanSupplier>[] testClasses = inv ? onlyIfNot : onlyIf;
for (Class<? extends BooleanSupplier> testClass : testClasses) {
BooleanSupplier bs = supplierFactory.get((Class<? extends BooleanSupplier>) testClass);
if (inv) {
addStep = and(addStep, not(bs));
} else {
addStep = and(addStep, bs);
}
}
}
addStep = and(addStep, supplierFactory, classOnlyIf, false);
addStep = and(addStep, supplierFactory, classOnlyIfNot, true);
addStep = and(addStep, supplierFactory, onlyIf, false);
addStep = and(addStep, supplierFactory, onlyIfNot, true);
final BooleanSupplier finalAddStep = addStep;

if (isRecorder) {
Expand Down Expand Up @@ -1013,6 +1017,19 @@ public String toString() {
return chainConfig;
}

private static BooleanSupplier and(BooleanSupplier addStep, BooleanSupplierFactoryBuildItem supplierFactory,
Class<? extends BooleanSupplier>[] testClasses, boolean inv) {
for (Class<? extends BooleanSupplier> testClass : testClasses) {
BooleanSupplier bs = supplierFactory.get((Class<? extends BooleanSupplier>) testClass);
if (inv) {
addStep = and(addStep, not(bs));
} else {
addStep = and(addStep, bs);
}
}
return addStep;
}

private static boolean isAnEmptyBuildItemProducer(Type parameterType) {
return isBuildProducerOf(parameterType, EmptyBuildItem.class)
|| isSupplierOf(parameterType, EmptyBuildItem.class)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package io.quarkus.deployment.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.function.BooleanSupplier;

/**
* Applies configuration to all build steps defined in the same class.
* <p>
* This annotation is applied at the class level, and will result in conditions ({@link #onlyIf()}/{@link #onlyIfNot()})
* being prepended to all build steps defined in that class.
* <p>
* This is mainly useful for "enabled"-type conditions, where all steps in a class should be enabled/disabled
* based on a single condition, for example based on configuration properties.
*
* @see BuildStep
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface BuildSteps {

/**
* Only include build steps defined in this class if the given supplier class(es) return {@code true}.
*
* @return the supplier class array
*/
Class<? extends BooleanSupplier>[] onlyIf() default {};

/**
* Only include build steps defined in this class if the given supplier class(es) return {@code false}.
*
* @return the supplier class array
*/
Class<? extends BooleanSupplier>[] onlyIfNot() default {};
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import io.quarkus.deployment.IsNormal;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.BuildSteps;
import io.quarkus.deployment.builditem.CuratedApplicationShutdownBuildItem;
import io.quarkus.deployment.builditem.DevServicesResultBuildItem;
import io.quarkus.deployment.builditem.DevServicesResultBuildItem.RunningDevService;
Expand All @@ -38,6 +39,7 @@
import io.quarkus.runtime.LaunchMode;
import io.quarkus.runtime.configuration.ConfigUtils;

@BuildSteps(onlyIfNot = IsNormal.class, onlyIf = GlobalDevServicesConfig.Enabled.class)
public class DevServicesDatasourceProcessor {

private static final Logger log = Logger.getLogger(DevServicesDatasourceProcessor.class);
Expand All @@ -48,7 +50,7 @@ public class DevServicesDatasourceProcessor {

static volatile boolean first = true;

@BuildStep(onlyIfNot = IsNormal.class, onlyIf = GlobalDevServicesConfig.Enabled.class)
@BuildStep
DevServicesDatasourceResultBuildItem launchDatabases(CurateOutcomeBuildItem curateOutcomeBuildItem,
DockerStatusBuildItem dockerStatusBuildItem,
List<DefaultDataSourceDbKindBuildItem> installedDrivers,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import io.quarkus.deployment.Feature;
import io.quarkus.deployment.IsNormal;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.BuildSteps;
import io.quarkus.deployment.builditem.CuratedApplicationShutdownBuildItem;
import io.quarkus.deployment.builditem.DevServicesResultBuildItem;
import io.quarkus.deployment.builditem.DevServicesSharedNetworkBuildItem;
Expand All @@ -35,6 +36,7 @@
/**
* Starts an Elasticsearch server as dev service if needed.
*/
@BuildSteps(onlyIfNot = IsNormal.class, onlyIf = GlobalDevServicesConfig.Enabled.class)
public class DevServicesElasticsearchProcessor {
private static final Logger log = Logger.getLogger(DevServicesElasticsearchProcessor.class);

Expand All @@ -52,7 +54,7 @@ public class DevServicesElasticsearchProcessor {
static volatile ElasticsearchDevServicesBuildTimeConfig cfg;
static volatile boolean first = true;

@BuildStep(onlyIfNot = IsNormal.class, onlyIf = GlobalDevServicesConfig.Enabled.class)
@BuildStep
public DevServicesResultBuildItem startElasticsearchDevService(
DockerStatusBuildItem dockerStatusBuildItem,
LaunchModeBuildItem launchMode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

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.AdditionalIndexedClassesBuildItem;
Expand All @@ -21,11 +22,12 @@
import io.quarkus.hibernate.search.orm.elasticsearch.deployment.HibernateSearchIntegrationStaticConfiguredBuildItem;
import io.quarkus.hibernate.search.orm.elasticsearch.runtime.HibernateSearchElasticsearchBuildTimeConfigPersistenceUnit;

@BuildSteps(onlyIf = HibernateSearchEnabled.class)
class HibernateSearchOutboxPollingProcessor {

private static final String HIBERNATE_SEARCH_ORM_COORDINATION_OUTBOX_POLLING = "Hibernate Search ORM - Coordination - Outbox polling";

@BuildStep(onlyIf = HibernateSearchEnabled.class)
@BuildStep
void registerInternalModel(BuildProducer<AdditionalIndexedClassesBuildItem> additionalIndexedClasses,
BuildProducer<ReflectiveClassBuildItem> reflectiveClasses,
BuildProducer<AdditionalJpaModelBuildItem> additionalJpaModel) {
Expand All @@ -38,7 +40,7 @@ void registerInternalModel(BuildProducer<AdditionalIndexedClassesBuildItem> addi
}
}

@BuildStep(onlyIf = HibernateSearchEnabled.class)
@BuildStep
@Record(ExecutionTime.STATIC_INIT)
void setStaticConfig(HibernateSearchOutboxPollingRecorder recorder,
List<HibernateSearchElasticsearchPersistenceUnitConfiguredBuildItem> configuredPersistenceUnits,
Expand All @@ -56,7 +58,7 @@ void setStaticConfig(HibernateSearchOutboxPollingRecorder recorder,
}
}

@BuildStep(onlyIf = HibernateSearchEnabled.class)
@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
void setRuntimeConfig(HibernateSearchOutboxPollingRecorder recorder,
HibernateSearchOutboxPollingRuntimeConfig runtimeConfig,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,19 @@
import io.quarkus.arc.processor.DotNames;
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.orm.PersistenceUnit;
import io.quarkus.hibernate.orm.runtime.PersistenceUnitUtil;
import io.quarkus.hibernate.search.orm.elasticsearch.runtime.HibernateSearchElasticsearchRecorder;
import io.quarkus.hibernate.search.orm.elasticsearch.runtime.HibernateSearchElasticsearchRuntimeConfig;

@BuildSteps(onlyIf = HibernateSearchEnabled.class)
public class HibernateSearchElasticsearchCdiProcessor {

@Record(ExecutionTime.RUNTIME_INIT)
@BuildStep(onlyIf = HibernateSearchEnabled.class)
@BuildStep
void generateSearchBeans(HibernateSearchElasticsearchRecorder recorder,
HibernateSearchElasticsearchRuntimeConfig runtimeConfig,
List<HibernateSearchElasticsearchPersistenceUnitConfiguredBuildItem> configuredPersistenceUnits,
Expand Down Expand Up @@ -67,7 +69,7 @@ private static <T> SyntheticBeanBuildItem createSyntheticBean(String persistence
return configurator.done();
}

@BuildStep(onlyIf = HibernateSearchEnabled.class)
@BuildStep
void registerAnnotations(BuildProducer<AdditionalBeanBuildItem> additionalBeans,
BuildProducer<BeanDefiningAnnotationBuildItem> beanDefiningAnnotations) {
// add the @SearchExtension class
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package io.quarkus.hibernate.search.orm.elasticsearch.deployment;

import static io.quarkus.hibernate.search.orm.elasticsearch.deployment.HibernateSearchElasticsearchProcessor.HIBERNATE_SEARCH_ELASTICSEARCH;

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.orm.deployment.PersistenceUnitDescriptorBuildItem;
import io.quarkus.hibernate.orm.deployment.integration.HibernateOrmIntegrationRuntimeConfiguredBuildItem;
import io.quarkus.hibernate.orm.deployment.integration.HibernateOrmIntegrationStaticConfiguredBuildItem;
import io.quarkus.hibernate.search.orm.elasticsearch.runtime.HibernateSearchElasticsearchRecorder;
import io.quarkus.hibernate.search.orm.elasticsearch.runtime.HibernateSearchElasticsearchRuntimeConfig;

@BuildSteps(onlyIfNot = HibernateSearchEnabled.class)
class HibernateSearchElasticsearchDisabledProcessor {

@BuildStep
@Record(ExecutionTime.STATIC_INIT)
public void disableHibernateSearchStaticInit(HibernateSearchElasticsearchRecorder recorder,
List<PersistenceUnitDescriptorBuildItem> persistenceUnitDescriptorBuildItems,
BuildProducer<HibernateOrmIntegrationStaticConfiguredBuildItem> staticIntegrations) {
for (PersistenceUnitDescriptorBuildItem puDescriptor : persistenceUnitDescriptorBuildItems) {
String puName = puDescriptor.getPersistenceUnitName();
staticIntegrations.produce(new HibernateOrmIntegrationStaticConfiguredBuildItem(HIBERNATE_SEARCH_ELASTICSEARCH,
puName).setInitListener(recorder.createStaticInitInactiveListener()));
}
}

@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
public void disableHibernateSearchRuntimeInit(HibernateSearchElasticsearchRecorder recorder,
HibernateSearchElasticsearchRuntimeConfig runtimeConfig,
List<PersistenceUnitDescriptorBuildItem> persistenceUnitDescriptorBuildItems,
BuildProducer<HibernateOrmIntegrationRuntimeConfiguredBuildItem> runtimeIntegrations) {
recorder.checkNoExplicitActiveTrue(runtimeConfig);
for (PersistenceUnitDescriptorBuildItem puDescriptor : persistenceUnitDescriptorBuildItems) {
String puName = puDescriptor.getPersistenceUnitName();
runtimeIntegrations.produce(new HibernateOrmIntegrationRuntimeConfiguredBuildItem(HIBERNATE_SEARCH_ELASTICSEARCH,
puName).setInitListener(recorder.createRuntimeInitInactiveListener()));
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.quarkus.hibernate.search.orm.elasticsearch.deployment;

import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.NativeImageFeatureBuildItem;
import io.quarkus.deployment.logging.LogCleanupFilterBuildItem;
import io.quarkus.deployment.pkg.steps.NativeOrNativeSourcesBuild;
import io.quarkus.hibernate.search.orm.elasticsearch.runtime.graal.DisableLoggingFeature;

// Note this is necessary even if Hibernate Search is disabled
class HibernateSearchElasticsearchLoggingProcessor {

@BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)
NativeImageFeatureBuildItem nativeImageFeature() {
return new NativeImageFeatureBuildItem(DisableLoggingFeature.class);
}

// Note this is necessary even if Hibernate Search is disabled
@BuildStep
void setupLogFilters(BuildProducer<LogCleanupFilterBuildItem> filters) {
// if the category changes, please also update DisableLoggingFeature in the runtime module
filters.produce(new LogCleanupFilterBuildItem(
"org.hibernate.search.mapper.orm.bootstrap.impl.HibernateSearchPreIntegrationService", "HSEARCH000034"));
}

}
Loading

0 comments on commit 80304e4

Please sign in to comment.