Skip to content

Commit

Permalink
Avoid creating CamelBeanBuildItem for health checks if they are disabled
Browse files Browse the repository at this point in the history
Fixes #3470
  • Loading branch information
jamesnetherton committed Jan 20, 2022
1 parent fc97c4b commit 73ffc7e
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.Collection;
import java.util.List;
import java.util.function.BooleanSupplier;
import java.util.function.Predicate;

import javax.enterprise.inject.Vetoed;

Expand All @@ -34,12 +35,17 @@
import org.apache.camel.health.HealthCheck;
import org.apache.camel.health.HealthCheckRegistry;
import org.apache.camel.health.HealthCheckRepository;
import org.apache.camel.impl.health.DefaultHealthCheckRegistry;
import org.apache.camel.impl.health.ConsumersHealthCheckRepository;
import org.apache.camel.impl.health.ContextHealthCheck;
import org.apache.camel.impl.health.HealthCheckRegistryRepository;
import org.apache.camel.impl.health.RoutesHealthCheckRepository;
import org.apache.camel.microprofile.health.AbstractCamelMicroProfileHealthCheck;
import org.apache.camel.quarkus.component.microprofile.health.runtime.CamelMicroProfileHealthConfig;
import org.apache.camel.quarkus.component.microprofile.health.runtime.CamelMicroProfileHealthRecorder;
import org.apache.camel.quarkus.core.deployment.spi.CamelBeanBuildItem;
import org.apache.camel.quarkus.core.deployment.util.CamelSupport;
import org.apache.camel.util.ObjectHelper;
import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;
import org.eclipse.microprofile.health.Liveness;
import org.eclipse.microprofile.health.Readiness;
Expand Down Expand Up @@ -79,46 +85,76 @@ public boolean getAsBoolean() {
}
}

static final class HealthRegistryEnabled implements BooleanSupplier {
@Override
public boolean getAsBoolean() {
return ConfigProvider.getConfig()
.getOptionalValue("camel.health.registryEnabled", boolean.class)
.orElse(true);
}
}

@BuildStep
FeatureBuildItem feature() {
return new FeatureBuildItem(FEATURE);
}

@Record(ExecutionTime.STATIC_INIT)
@BuildStep(onlyIf = HealthEnabled.class)
CamelBeanBuildItem metricRegistry(CamelMicroProfileHealthRecorder recorder, CamelMicroProfileHealthConfig config) {
@BuildStep(onlyIf = { HealthEnabled.class, HealthRegistryEnabled.class })
CamelBeanBuildItem healthCheckRegistry(CamelMicroProfileHealthRecorder recorder, CamelMicroProfileHealthConfig config) {
return new CamelBeanBuildItem(
"HealthCheckRegistry",
HealthCheckRegistry.class.getName(),
recorder.createHealthCheckRegistry(config));
}

@BuildStep(onlyIf = HealthEnabled.class)
List<CamelBeanBuildItem> camelHealthDiscovery(
CombinedIndexBuildItem combinedIndex,
CamelMicroProfileHealthConfig config) {

List<CamelBeanBuildItem> camelHealthDiscovery(CombinedIndexBuildItem combinedIndex) {
IndexView index = combinedIndex.getIndex();
List<CamelBeanBuildItem> buildItems = new ArrayList<>();
Collection<ClassInfo> healthChecks = index.getAllKnownImplementors(CAMEL_HEALTH_CHECK_DOTNAME);
Collection<ClassInfo> healthCheckRepositories = index
.getAllKnownImplementors(CAMEL_HEALTH_CHECK_REPOSITORY_DOTNAME);

Config config = ConfigProvider.getConfig();
Predicate<ClassInfo> healthCheckFilter = classInfo -> {
String className = classInfo.name().toString();
if (className.equals(HealthCheckRegistryRepository.class.getName())) {
// HealthCheckRegistryRepository is created internally by Camel
return false;
}

if (className.equals(ContextHealthCheck.class.getName())) {
return config.getOptionalValue("camel.health.contextEnabled", boolean.class).orElse(true);
}

if (className.equals(RoutesHealthCheckRepository.class.getName())) {
return config.getOptionalValue("camel.health.routesEnabled", boolean.class).orElse(true);
}

if (className.equals(ConsumersHealthCheckRepository.class.getName())) {
return config.getOptionalValue("camel.health.consumersEnabled", boolean.class).orElse(true);
}

return true;
};

// Create CamelBeanBuildItem to bind instances of HealthCheck to the camel registry
healthChecks.stream()
.filter(CamelSupport::isConcrete)
.filter(CamelSupport::isPublic)
.filter(ClassInfo::hasNoArgsConstructor)
.map(classInfo -> new CamelBeanBuildItem(classInfo.simpleName(), classInfo.name().toString()))
.filter(healthCheckFilter)
.map(this::createHealthCamelBeanBuildItem)
.forEach(buildItems::add);

// Create CamelBeanBuildItem to bind instances of HealthCheckRepository to the camel registry
healthCheckRepositories.stream()
.filter(CamelSupport::isConcrete)
.filter(CamelSupport::isPublic)
.filter(ClassInfo::hasNoArgsConstructor)
.filter(classInfo -> !classInfo.simpleName().equals(DefaultHealthCheckRegistry.class.getSimpleName()))
.map(classInfo -> new CamelBeanBuildItem(classInfo.simpleName(), classInfo.name().toString()))
.filter(healthCheckFilter)
.map(this::createHealthCamelBeanBuildItem)
.forEach(buildItems::add);

return buildItems;
Expand All @@ -145,4 +181,30 @@ private boolean isCamelMicroProfileHealthCheck(ClassInfo classInfo) {
&& (classInfo.classAnnotation(MICROPROFILE_LIVENESS_DOTNAME) != null
|| classInfo.classAnnotation(MICROPROFILE_READINESS_DOTNAME) != null);
}

private CamelBeanBuildItem createHealthCamelBeanBuildItem(ClassInfo classInfo) {
String beanName;
String className = classInfo.name().toString();
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

try {
Class<?> clazz = classLoader.loadClass(className);
Object health = clazz.getDeclaredConstructor().newInstance();
if (health instanceof HealthCheck) {
beanName = ((HealthCheck) health).getId();
} else if (health instanceof HealthCheckRepository) {
beanName = ((HealthCheckRepository) health).getId();
} else {
throw new IllegalArgumentException("Unknown health type " + className);
}

if (ObjectHelper.isEmpty(beanName)) {
beanName = className;
}

return new CamelBeanBuildItem(beanName, className);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.quarkus.component.microprofile.health.deployment;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Properties;
import java.util.Set;

import javax.inject.Inject;

import io.quarkus.test.QuarkusUnitTest;
import org.apache.camel.CamelContext;
import org.apache.camel.health.HealthCheckRegistry;
import org.apache.camel.impl.health.ConsumersHealthCheckRepository;
import org.apache.camel.impl.health.ContextHealthCheck;
import org.apache.camel.impl.health.RoutesHealthCheckRepository;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.Asset;
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 static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class MicroProfileHealthCamelChecksDisabledTest {

@RegisterExtension
static final QuarkusUnitTest CONFIG = new QuarkusUnitTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addAsResource(applicationProperties(), "application.properties"));

@Inject
CamelContext context;

public static final Asset applicationProperties() {
Writer writer = new StringWriter();

Properties props = new Properties();
props.put("camel.health.contextEnabled", "false");
props.put("camel.health.routesEnabled", "false");
props.put("camel.health.consumersEnabled", "false");
props.put("camel.health.registryEnabled", "false");

try {
props.store(writer, "");
} catch (IOException e) {
throw new RuntimeException(e);
}

return new StringAsset(writer.toString());
}

@Test
public void contextHealthCheckNull() {
ContextHealthCheck contextHealthCheck = context.getRegistry().lookupByNameAndType("context", ContextHealthCheck.class);
assertNull(contextHealthCheck);
}

@Test
public void routesHealthCheckNull() {
RoutesHealthCheckRepository routesRepository = context.getRegistry().lookupByNameAndType("routes",
RoutesHealthCheckRepository.class);
assertNull(routesRepository);
}

@Test
public void consumersHealthCheckNull() {
ConsumersHealthCheckRepository consumersRepository = context.getRegistry().lookupByNameAndType("consumers",
ConsumersHealthCheckRepository.class);
assertNull(consumersRepository);
}

@Test
public void healthRegistryNull() {
Set<HealthCheckRegistry> healthCheckRegistries = context.getRegistry().findByType(HealthCheckRegistry.class);
assertTrue(healthCheckRegistries.isEmpty());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,17 @@
import io.quarkus.test.QuarkusUnitTest;
import org.apache.camel.CamelContext;
import org.apache.camel.health.HealthCheckRegistry;
import org.apache.camel.impl.health.ConsumersHealthCheckRepository;
import org.apache.camel.impl.health.ContextHealthCheck;
import org.apache.camel.impl.health.DefaultHealthCheckRegistry;
import org.eclipse.microprofile.health.HealthCheck;
import org.apache.camel.impl.health.RoutesHealthCheckRepository;
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 static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class MicroProfileHealthEnabledTest {
Expand All @@ -52,9 +55,22 @@ public void healthCheckRegistryBeanNotNull() {
}

@Test
public void camelMicroProfileHealthCheckBeansNotNull() {
Set<HealthCheck> healthChecks = context.getRegistry().findByType(HealthCheck.class);
assertEquals(2, healthChecks.size());
public void contextHealthCheckNotNull() {
ContextHealthCheck contextHealthCheck = context.getRegistry().lookupByNameAndType("context", ContextHealthCheck.class);
assertNotNull(contextHealthCheck);
}

@Test
public void routesHealthCheckNotNull() {
RoutesHealthCheckRepository routesRepository = context.getRegistry().lookupByNameAndType("routes",
RoutesHealthCheckRepository.class);
assertNotNull(routesRepository);
}

@Test
public void consumersHealthCheckNotNull() {
ConsumersHealthCheckRepository consumersRepository = context.getRegistry().lookupByNameAndType("consumers",
ConsumersHealthCheckRepository.class);
assertNotNull(consumersRepository);
}
}

0 comments on commit 73ffc7e

Please sign in to comment.