This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
commit 09e570ab42e6b89730642a57f42fde90762dd724 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Tue Nov 30 11:51:35 2021 +0100 CAMEL-15133: camel-health - Resolve health-checks from classpath and make it friendlier to provide custom health checks. --- .../camel/spi/annotations/ConstantProvider.java | 3 + .../{ConstantProvider.java => HealthCheck.java} | 12 ++- .../org/apache/camel/ExtendedCamelContext.java | 15 +++ .../apache/camel/health/HealthCheckRegistry.java | 7 +- .../apache/camel/health/HealthCheckResolver.java | 28 +++++ .../camel/impl/engine/AbstractCamelContext.java | 22 ++++ .../impl/engine/DefaultDataFormatResolver.java | 1 + .../impl/engine/DefaultHealthCheckResolver.java | 119 +++++++++++++++++++++ .../camel/impl/engine/SimpleCamelContext.java | 6 ++ .../camel/impl/ExtendedCamelContextConfigurer.java | 6 ++ .../camel/impl/lw/LightweightCamelContext.java | 11 ++ .../impl/lw/LightweightRuntimeCamelContext.java | 13 +++ .../camel/impl/health/MyFooHealthCheck.java} | 29 +++-- .../camel/impl/health/MyFooHealthCheckTest.java | 48 +++++++++ .../org/apache/camel/health-check/myfoo-check | 18 ++++ .../consumers-repository} | 0 .../context-check} | 0 .../default-registry} | 0 .../routes-repository} | 0 .../health/ConsumersHealthCheckRepository.java | 4 +- .../camel/impl/health/ContextHealthCheck.java | 3 +- .../impl/health/DefaultHealthCheckRegistry.java | 28 ++--- .../impl/health/RoutesHealthCheckRepository.java | 4 +- .../modules/ROOT/pages/health-check.adoc | 2 +- .../camel/spi/annotations/ConstantProvider.java | 3 + .../apache/camel/spi/annotations/HealthCheck.java | 12 ++- 26 files changed, 351 insertions(+), 43 deletions(-) diff --git a/core/camel-api/src/generated/java/org/apache/camel/spi/annotations/ConstantProvider.java b/core/camel-api/src/generated/java/org/apache/camel/spi/annotations/ConstantProvider.java index 6c756d0..44e44bf 100644 --- a/core/camel-api/src/generated/java/org/apache/camel/spi/annotations/ConstantProvider.java +++ b/core/camel-api/src/generated/java/org/apache/camel/spi/annotations/ConstantProvider.java @@ -22,6 +22,9 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Internal annotation to mark a class as having constant fields for the source code generator. + */ @Retention(RetentionPolicy.RUNTIME) @Documented @Target({ ElementType.TYPE }) diff --git a/core/camel-api/src/generated/java/org/apache/camel/spi/annotations/ConstantProvider.java b/core/camel-api/src/generated/java/org/apache/camel/spi/annotations/HealthCheck.java similarity index 72% copy from core/camel-api/src/generated/java/org/apache/camel/spi/annotations/ConstantProvider.java copy to core/camel-api/src/generated/java/org/apache/camel/spi/annotations/HealthCheck.java index 6c756d0..7a539f4 100644 --- a/core/camel-api/src/generated/java/org/apache/camel/spi/annotations/ConstantProvider.java +++ b/core/camel-api/src/generated/java/org/apache/camel/spi/annotations/HealthCheck.java @@ -22,11 +22,21 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Marks a class as a custom health-check or health-check repository. + */ @Retention(RetentionPolicy.RUNTIME) @Documented @Target({ ElementType.TYPE }) -public @interface ConstantProvider { +@ServiceFactory("health-check") +public @interface HealthCheck { + /** + * The ID of the health check. + * + * Use <tt>-check</tt> as prefix for health checks, and use <tt>-repository</tt> as prefix for health-check repository. + * For example to use myfoo as the ID for a health-check, then set this value as <tt>myfoo-check</tt>. + */ String value(); } diff --git a/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java b/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java index 0caf420..26a029b 100644 --- a/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java +++ b/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java @@ -22,6 +22,7 @@ import java.util.Set; import java.util.concurrent.ScheduledExecutorService; import org.apache.camel.catalog.RuntimeCamelCatalog; +import org.apache.camel.health.HealthCheckResolver; import org.apache.camel.spi.AnnotationBasedProcessorFactory; import org.apache.camel.spi.AsyncProcessorAwaitManager; import org.apache.camel.spi.BeanIntrospection; @@ -335,6 +336,20 @@ public interface ExtendedCamelContext extends CamelContext { void setDataFormatResolver(DataFormatResolver dataFormatResolver); /** + * Gets the current health check resolver + * + * @return the resolver + */ + HealthCheckResolver getHealthCheckResolver(); + + /** + * Sets a custom health check resolver + * + * @param healthCheckResolver the resolver + */ + void setHealthCheckResolver(HealthCheckResolver healthCheckResolver); + + /** * Returns the package scanning class resolver * * @return the resolver diff --git a/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckRegistry.java b/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckRegistry.java index 323a07f..c2b3523 100644 --- a/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckRegistry.java +++ b/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckRegistry.java @@ -33,9 +33,14 @@ import org.apache.camel.util.ObjectHelper; public interface HealthCheckRegistry extends CamelContextAware, StaticService, IdAware { /** + * Service factory name. + */ + String NAME = "default-registry"; + + /** * Service factory key. */ - String FACTORY = "health-check-registry"; + String FACTORY = "health-check/" + NAME; /** * Whether Health Check is enabled globally diff --git a/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckResolver.java b/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckResolver.java new file mode 100644 index 0000000..547284c --- /dev/null +++ b/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckResolver.java @@ -0,0 +1,28 @@ +package org.apache.camel.health; + +import org.apache.camel.CamelContext; + +/** + * A pluggable strategy for resolving health checks in a loosely coupled manner + */ +public interface HealthCheckResolver { + + /** + * Resolves the given {@link HealthCheck}. + * + * @param id the id of the {@link HealthCheck} + * @param context the camel context + * @return the resolved {@link HealthCheck}, or <tt>null</tt> if not found + */ + HealthCheck resolveHealthCheck(String id, CamelContext context); + + /** + * Resolves the given {@link HealthCheckRepository}. + * + * @param id the id of the {@link HealthCheckRepository} + * @param context the camel context + * @return the resolved {@link HealthCheckRepository}, or <tt>null</tt> if not found + */ + HealthCheckRepository resolveHealthCheckRepository(String id, CamelContext context); + +} diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java index aaf9066..87905f6 100644 --- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java +++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java @@ -81,6 +81,7 @@ import org.apache.camel.VetoCamelContextStartException; import org.apache.camel.api.management.JmxSystemPropertyKeys; import org.apache.camel.catalog.RuntimeCamelCatalog; import org.apache.camel.health.HealthCheckRegistry; +import org.apache.camel.health.HealthCheckResolver; import org.apache.camel.spi.AnnotationBasedProcessorFactory; import org.apache.camel.spi.AnnotationScanTypeConverters; import org.apache.camel.spi.AsyncProcessorAwaitManager; @@ -290,6 +291,7 @@ public abstract class AbstractCamelContext extends BaseService private volatile ConfigurerResolver configurerResolver; private volatile UriFactoryResolver uriFactoryResolver; private volatile DataFormatResolver dataFormatResolver; + private volatile HealthCheckResolver healthCheckResolver; private volatile ManagementStrategy managementStrategy; private volatile ManagementMBeanAssembler managementMBeanAssembler; private volatile RestRegistryFactory restRegistryFactory; @@ -3755,6 +3757,7 @@ public abstract class AbstractCamelContext extends BaseService getComponentResolver(); getComponentNameResolver(); getDataFormatResolver(); + getHealthCheckResolver(); getExecutorServiceManager(); getExchangeFactoryManager(); @@ -4333,6 +4336,23 @@ public abstract class AbstractCamelContext extends BaseService } @Override + public HealthCheckResolver getHealthCheckResolver() { + if (healthCheckResolver == null) { + synchronized (lock) { + if (healthCheckResolver == null) { + setHealthCheckResolver(createHealthCheckResolver()); + } + } + } + return healthCheckResolver; + } + + @Override + public void setHealthCheckResolver(HealthCheckResolver healthCheckResolver) { + this.healthCheckResolver = doAddService(healthCheckResolver); + } + + @Override public ShutdownStrategy getShutdownStrategy() { if (shutdownStrategy == null) { synchronized (lock) { @@ -5028,6 +5048,8 @@ public abstract class AbstractCamelContext extends BaseService protected abstract DataFormatResolver createDataFormatResolver(); + protected abstract HealthCheckResolver createHealthCheckResolver(); + protected abstract MessageHistoryFactory createMessageHistoryFactory(); protected abstract InflightRepository createInflightRepository(); diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultDataFormatResolver.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultDataFormatResolver.java index 525cba8..dd7664d 100644 --- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultDataFormatResolver.java +++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultDataFormatResolver.java @@ -28,6 +28,7 @@ import org.apache.camel.support.ResolverHelper; * Default data format resolver */ public class DefaultDataFormatResolver implements DataFormatResolver { + public static final String DATAFORMAT_RESOURCE_PATH = "META-INF/services/org/apache/camel/dataformat/"; private FactoryFinder dataformatFactory; diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultHealthCheckResolver.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultHealthCheckResolver.java new file mode 100644 index 0000000..08b8c29 --- /dev/null +++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultHealthCheckResolver.java @@ -0,0 +1,119 @@ +/* + * 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.impl.engine; + +import org.apache.camel.CamelContext; +import org.apache.camel.ExtendedCamelContext; +import org.apache.camel.NoFactoryAvailableException; +import org.apache.camel.health.HealthCheck; +import org.apache.camel.health.HealthCheckRepository; +import org.apache.camel.health.HealthCheckResolver; +import org.apache.camel.spi.FactoryFinder; + +/** + * Default health check resolver that looks for health checks factories in + * <b>META-INF/services/org/apache/camel/health-check/</b>. + */ +public class DefaultHealthCheckResolver implements HealthCheckResolver { + + public static final String HEALTH_CHECK_RESOURCE_PATH = "META-INF/services/org/apache/camel/health-check/"; + + protected FactoryFinder healthCheckFactory; + + @Override + public HealthCheck resolveHealthCheck(String id, CamelContext context) { + // lookup in registry first + HealthCheck answer = context.getRegistry().lookupByNameAndType(id + "-health-check", HealthCheck.class); + if (answer == null) { + answer = context.getRegistry().lookupByNameAndType(id, HealthCheck.class); + } + if (answer != null) { + return answer; + } + + Class<?> type = null; + try { + type = findHealthCheck(id, context); + } catch (NoFactoryAvailableException e) { + // ignore + } catch (Exception e) { + throw new IllegalArgumentException("Invalid URI, no HealthCheck registered for id: " + id, e); + } + + if (type != null) { + if (HealthCheck.class.isAssignableFrom(type)) { + return (HealthCheck) context.getInjector().newInstance(type, false); + } else { + throw new IllegalArgumentException( + "Resolving health-check: " + id + " detected type conflict: Not a HealthCheck implementation. Found: " + + type.getName()); + } + } + + return null; + } + + @Override + public HealthCheckRepository resolveHealthCheckRepository(String id, CamelContext context) { + // lookup in registry first + HealthCheckRepository answer + = context.getRegistry().lookupByNameAndType(id + "-health-check-repository", HealthCheckRepository.class); + if (answer == null) { + answer = context.getRegistry().lookupByNameAndType(id, HealthCheckRepository.class); + } + if (answer != null) { + return answer; + } + + Class<?> type = null; + try { + type = findHealthCheckRepository(id, context); + } catch (NoFactoryAvailableException e) { + // ignore + } catch (Exception e) { + throw new IllegalArgumentException("Invalid URI, no HealthCheckRepository registered for id: " + id, e); + } + + if (type != null) { + if (HealthCheckRepository.class.isAssignableFrom(type)) { + return (HealthCheckRepository) context.getInjector().newInstance(type, false); + } else { + throw new IllegalArgumentException( + "Resolving health-check-repository: " + id + + " detected type conflict: Not a HealthCheckRepository implementation. Found: " + + type.getName()); + } + } + + return null; + } + + protected Class<?> findHealthCheck(String name, CamelContext context) throws Exception { + if (healthCheckFactory == null) { + healthCheckFactory = context.adapt(ExtendedCamelContext.class).getFactoryFinder(HEALTH_CHECK_RESOURCE_PATH); + } + return healthCheckFactory.findOptionalClass(name + "-check").orElse(null); + } + + protected Class<?> findHealthCheckRepository(String name, CamelContext context) throws Exception { + if (healthCheckFactory == null) { + healthCheckFactory = context.adapt(ExtendedCamelContext.class).getFactoryFinder(HEALTH_CHECK_RESOURCE_PATH); + } + return healthCheckFactory.findOptionalClass(name + "-repository").orElse(null); + } + +} diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java index 9dee233..8d02c26 100644 --- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java +++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java @@ -27,6 +27,7 @@ import org.apache.camel.RouteTemplateContext; import org.apache.camel.TypeConverter; import org.apache.camel.catalog.RuntimeCamelCatalog; import org.apache.camel.health.HealthCheckRegistry; +import org.apache.camel.health.HealthCheckResolver; import org.apache.camel.impl.converter.DefaultTypeConverter; import org.apache.camel.spi.AnnotationBasedProcessorFactory; import org.apache.camel.spi.AsyncProcessorAwaitManager; @@ -277,6 +278,11 @@ public class SimpleCamelContext extends AbstractCamelContext { } @Override + protected HealthCheckResolver createHealthCheckResolver() { + return new DefaultHealthCheckResolver(); + } + + @Override protected MessageHistoryFactory createMessageHistoryFactory() { return new DefaultMessageHistoryFactory(); } diff --git a/core/camel-core-engine/src/generated/java/org/apache/camel/impl/ExtendedCamelContextConfigurer.java b/core/camel-core-engine/src/generated/java/org/apache/camel/impl/ExtendedCamelContextConfigurer.java index 90c0b6d..698e937 100644 --- a/core/camel-core-engine/src/generated/java/org/apache/camel/impl/ExtendedCamelContextConfigurer.java +++ b/core/camel-core-engine/src/generated/java/org/apache/camel/impl/ExtendedCamelContextConfigurer.java @@ -79,6 +79,8 @@ public class ExtendedCamelContextConfigurer extends org.apache.camel.support.com case "GlobalOptions": target.setGlobalOptions(property(camelContext, java.util.Map.class, value)); return true; case "headersmapfactory": case "HeadersMapFactory": target.setHeadersMapFactory(property(camelContext, org.apache.camel.spi.HeadersMapFactory.class, value)); return true; + case "healthcheckresolver": + case "HealthCheckResolver": target.setHealthCheckResolver(property(camelContext, org.apache.camel.health.HealthCheckResolver.class, value)); return true; case "inflightrepository": case "InflightRepository": target.setInflightRepository(property(camelContext, org.apache.camel.spi.InflightRepository.class, value)); return true; case "injector": @@ -258,6 +260,8 @@ public class ExtendedCamelContextConfigurer extends org.apache.camel.support.com case "GlobalOptions": return java.util.Map.class; case "headersmapfactory": case "HeadersMapFactory": return org.apache.camel.spi.HeadersMapFactory.class; + case "healthcheckresolver": + case "HealthCheckResolver": return org.apache.camel.health.HealthCheckResolver.class; case "inflightrepository": case "InflightRepository": return org.apache.camel.spi.InflightRepository.class; case "injector": @@ -438,6 +442,8 @@ public class ExtendedCamelContextConfigurer extends org.apache.camel.support.com case "GlobalOptions": return target.getGlobalOptions(); case "headersmapfactory": case "HeadersMapFactory": return target.getHeadersMapFactory(); + case "healthcheckresolver": + case "HealthCheckResolver": return target.getHealthCheckResolver(); case "inflightrepository": case "InflightRepository": return target.getInflightRepository(); case "injector": diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java index 1ed731c..222df1e 100644 --- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java +++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java @@ -54,6 +54,7 @@ import org.apache.camel.TypeConverter; import org.apache.camel.ValueHolder; import org.apache.camel.builder.AdviceWithRouteBuilder; import org.apache.camel.catalog.RuntimeCamelCatalog; +import org.apache.camel.health.HealthCheckResolver; import org.apache.camel.impl.DefaultCamelContext; import org.apache.camel.model.DataFormatDefinition; import org.apache.camel.model.FaultToleranceConfigurationDefinition; @@ -1268,6 +1269,16 @@ public class LightweightCamelContext implements ExtendedCamelContext, CatalogCam } @Override + public HealthCheckResolver getHealthCheckResolver() { + return getExtendedCamelContext().getHealthCheckResolver(); + } + + @Override + public void setHealthCheckResolver(HealthCheckResolver healthCheckResolver) { + getExtendedCamelContext().setHealthCheckResolver(healthCheckResolver); + } + + @Override public PackageScanClassResolver getPackageScanClassResolver() { return getExtendedCamelContext().getPackageScanClassResolver(); } diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java index 4460e9d..348c627 100644 --- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java +++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java @@ -62,6 +62,7 @@ import org.apache.camel.StartupSummaryLevel; import org.apache.camel.TypeConverter; import org.apache.camel.ValueHolder; import org.apache.camel.catalog.RuntimeCamelCatalog; +import org.apache.camel.health.HealthCheckResolver; import org.apache.camel.impl.converter.CoreTypeConverterRegistry; import org.apache.camel.impl.engine.DefaultComponentResolver; import org.apache.camel.impl.engine.DefaultDataFormatResolver; @@ -165,6 +166,7 @@ public class LightweightRuntimeCamelContext implements ExtendedCamelContext, Cat private final ComponentNameResolver componentNameResolver; private final LanguageResolver languageResolver; private final DataFormatResolver dataFormatResolver; + private final HealthCheckResolver healthCheckResolver; private final UuidGenerator uuidGenerator; private final EndpointRegistry<? extends ValueHolder<String>> endpoints; private final Map<String, Component> components; @@ -214,6 +216,7 @@ public class LightweightRuntimeCamelContext implements ExtendedCamelContext, Cat componentNameResolver = context.adapt(ExtendedCamelContext.class).getComponentNameResolver(); languageResolver = context.adapt(ExtendedCamelContext.class).getLanguageResolver(); dataFormatResolver = context.adapt(ExtendedCamelContext.class).getDataFormatResolver(); + healthCheckResolver = context.adapt(ExtendedCamelContext.class).getHealthCheckResolver(); endpoints = context.getEndpointRegistry(); components = context.getComponentNames().stream().collect(Collectors.toMap(s -> s, context::hasComponent)); languages = context.getLanguageNames().stream().collect(Collectors.toMap(s -> s, context::resolveLanguage)); @@ -558,6 +561,16 @@ public class LightweightRuntimeCamelContext implements ExtendedCamelContext, Cat } @Override + public HealthCheckResolver getHealthCheckResolver() { + return healthCheckResolver; + } + + @Override + public void setHealthCheckResolver(HealthCheckResolver healthCheckResolver) { + throw new UnsupportedOperationException(); + } + + @Override public UuidGenerator getUuidGenerator() { return uuidGenerator; } diff --git a/core/camel-api/src/generated/java/org/apache/camel/spi/annotations/ConstantProvider.java b/core/camel-core/src/test/java/org/apache/camel/impl/health/MyFooHealthCheck.java similarity index 59% copy from core/camel-api/src/generated/java/org/apache/camel/spi/annotations/ConstantProvider.java copy to core/camel-core/src/test/java/org/apache/camel/impl/health/MyFooHealthCheck.java index 6c756d0..8348266 100644 --- a/core/camel-api/src/generated/java/org/apache/camel/spi/annotations/ConstantProvider.java +++ b/core/camel-core/src/test/java/org/apache/camel/impl/health/MyFooHealthCheck.java @@ -14,19 +14,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.spi.annotations; +package org.apache.camel.impl.health; -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +import java.util.Map; -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Target({ ElementType.TYPE }) -public @interface ConstantProvider { +import org.apache.camel.health.HealthCheckResultBuilder; +import org.apache.camel.spi.annotations.HealthCheck; - String value(); +/** + * Custom health check. + */ +@HealthCheck("myfoo-check") +public class MyFooHealthCheck extends AbstractHealthCheck { + + public MyFooHealthCheck() { + super("acme", "myfoo"); + } + @Override + protected void doCall(HealthCheckResultBuilder builder, Map<String, Object> options) { + builder.state(State.DOWN); + builder.message("Chaos Monkey was here"); + } } diff --git a/core/camel-core/src/test/java/org/apache/camel/impl/health/MyFooHealthCheckTest.java b/core/camel-core/src/test/java/org/apache/camel/impl/health/MyFooHealthCheckTest.java new file mode 100644 index 0000000..1e3b506 --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/impl/health/MyFooHealthCheckTest.java @@ -0,0 +1,48 @@ +/* + * 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.impl.health; + +import org.apache.camel.ContextTestSupport; +import org.apache.camel.ExtendedCamelContext; +import org.apache.camel.health.HealthCheck; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class MyFooHealthCheckTest extends ContextTestSupport { + + @Override + public boolean isUseRouteBuilder() { + return false; + } + + @Test + public void testMyFoo() throws Exception { + context.start(); + + HealthCheck hc + = context.adapt(ExtendedCamelContext.class).getHealthCheckResolver().resolveHealthCheck("myfoo", context); + Assertions.assertNotNull(hc); + + Assertions.assertEquals("acme", hc.getGroup()); + Assertions.assertEquals("myfoo", hc.getId()); + + HealthCheck.Result r = hc.call(); + + Assertions.assertEquals(HealthCheck.State.DOWN, r.getState()); + Assertions.assertEquals("Chaos Monkey was here", r.getMessage().get()); + } +} diff --git a/core/camel-core/src/test/resources/META-INF/services/org/apache/camel/health-check/myfoo-check b/core/camel-core/src/test/resources/META-INF/services/org/apache/camel/health-check/myfoo-check new file mode 100644 index 0000000..e66e0a6 --- /dev/null +++ b/core/camel-core/src/test/resources/META-INF/services/org/apache/camel/health-check/myfoo-check @@ -0,0 +1,18 @@ +# +# 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. +# + +class=org.apache.camel.impl.health.MyFooHealthCheck \ No newline at end of file diff --git a/core/camel-health/src/generated/resources/META-INF/services/org/apache/camel/consumers-health-check-repository b/core/camel-health/src/generated/resources/META-INF/services/org/apache/camel/health-check/consumers-repository similarity index 100% rename from core/camel-health/src/generated/resources/META-INF/services/org/apache/camel/consumers-health-check-repository rename to core/camel-health/src/generated/resources/META-INF/services/org/apache/camel/health-check/consumers-repository diff --git a/core/camel-health/src/generated/resources/META-INF/services/org/apache/camel/context-health-check b/core/camel-health/src/generated/resources/META-INF/services/org/apache/camel/health-check/context-check similarity index 100% rename from core/camel-health/src/generated/resources/META-INF/services/org/apache/camel/context-health-check rename to core/camel-health/src/generated/resources/META-INF/services/org/apache/camel/health-check/context-check diff --git a/core/camel-health/src/generated/resources/META-INF/services/org/apache/camel/health-check-registry b/core/camel-health/src/generated/resources/META-INF/services/org/apache/camel/health-check/default-registry similarity index 100% rename from core/camel-health/src/generated/resources/META-INF/services/org/apache/camel/health-check-registry rename to core/camel-health/src/generated/resources/META-INF/services/org/apache/camel/health-check/default-registry diff --git a/core/camel-health/src/generated/resources/META-INF/services/org/apache/camel/routes-health-check-repository b/core/camel-health/src/generated/resources/META-INF/services/org/apache/camel/health-check/routes-repository similarity index 100% rename from core/camel-health/src/generated/resources/META-INF/services/org/apache/camel/routes-health-check-repository rename to core/camel-health/src/generated/resources/META-INF/services/org/apache/camel/health-check/routes-repository diff --git a/core/camel-health/src/main/java/org/apache/camel/impl/health/ConsumersHealthCheckRepository.java b/core/camel-health/src/main/java/org/apache/camel/impl/health/ConsumersHealthCheckRepository.java index 4504ada..79ce263 100644 --- a/core/camel-health/src/main/java/org/apache/camel/impl/health/ConsumersHealthCheckRepository.java +++ b/core/camel-health/src/main/java/org/apache/camel/impl/health/ConsumersHealthCheckRepository.java @@ -30,15 +30,15 @@ import org.apache.camel.Route; import org.apache.camel.health.HealthCheck; import org.apache.camel.health.HealthCheckConfiguration; import org.apache.camel.health.HealthCheckRepository; -import org.apache.camel.spi.annotations.JdkService; import org.apache.camel.support.PatternHelper; /** * Repository for consumers {@link HealthCheck}s. */ -@JdkService("consumers-health-check-repository") +@org.apache.camel.spi.annotations.HealthCheck("consumers-repository") @DeferredContextBinding public class ConsumersHealthCheckRepository implements CamelContextAware, HealthCheckRepository { + private final ConcurrentMap<Consumer, HealthCheck> checks; private volatile CamelContext context; private Map<String, HealthCheckConfiguration> configurations; diff --git a/core/camel-health/src/main/java/org/apache/camel/impl/health/ContextHealthCheck.java b/core/camel-health/src/main/java/org/apache/camel/impl/health/ContextHealthCheck.java index b2f9f71..622451b 100644 --- a/core/camel-health/src/main/java/org/apache/camel/impl/health/ContextHealthCheck.java +++ b/core/camel-health/src/main/java/org/apache/camel/impl/health/ContextHealthCheck.java @@ -20,13 +20,12 @@ import java.util.Map; import org.apache.camel.CamelContext; import org.apache.camel.health.HealthCheckResultBuilder; -import org.apache.camel.spi.annotations.JdkService; /** * {@link org.apache.camel.health.HealthCheck} that checks the status of the {@link CamelContext} whether its started or * not. */ -@JdkService("context-health-check") +@org.apache.camel.spi.annotations.HealthCheck("context-check") public final class ContextHealthCheck extends AbstractHealthCheck { private CamelContext camelContext; diff --git a/core/camel-health/src/main/java/org/apache/camel/impl/health/DefaultHealthCheckRegistry.java b/core/camel-health/src/main/java/org/apache/camel/impl/health/DefaultHealthCheckRegistry.java index 8236120..7d2140b 100644 --- a/core/camel-health/src/main/java/org/apache/camel/impl/health/DefaultHealthCheckRegistry.java +++ b/core/camel-health/src/main/java/org/apache/camel/impl/health/DefaultHealthCheckRegistry.java @@ -28,8 +28,7 @@ import org.apache.camel.ExtendedCamelContext; import org.apache.camel.health.HealthCheck; import org.apache.camel.health.HealthCheckRegistry; import org.apache.camel.health.HealthCheckRepository; -import org.apache.camel.spi.FactoryFinder; -import org.apache.camel.spi.annotations.JdkService; +import org.apache.camel.health.HealthCheckResolver; import org.apache.camel.support.service.ServiceSupport; import org.apache.camel.util.ObjectHelper; import org.slf4j.Logger; @@ -38,7 +37,7 @@ import org.slf4j.LoggerFactory; /** * Default {@link HealthCheckRegistry}. */ -@JdkService(HealthCheckRegistry.FACTORY) +@org.apache.camel.spi.annotations.HealthCheck(HealthCheckRegistry.NAME) @DeferredContextBinding public class DefaultHealthCheckRegistry extends ServiceSupport implements HealthCheckRegistry { private static final Logger LOG = LoggerFactory.getLogger(DefaultHealthCheckRegistry.class); @@ -123,16 +122,8 @@ public class DefaultHealthCheckRegistry extends ServiceSupport implements Health HealthCheck answer = checks.stream().filter(h -> h.getId().equals(id)).findFirst() .orElse(camelContext.getRegistry().findByTypeWithName(HealthCheck.class).get(id)); if (answer == null) { - // discover via classpath (try first via -health-check and then id as-is) - FactoryFinder ff = camelContext.adapt(ExtendedCamelContext.class).getDefaultFactoryFinder(); - Class<? extends HealthCheck> clazz - = (Class<? extends HealthCheck>) ff.findOptionalClass(id + "-health-check").orElse(null); - if (clazz == null) { - clazz = (Class<? extends HealthCheck>) ff.findOptionalClass(id).orElse(null); - } - if (clazz != null) { - answer = camelContext.getInjector().newInstance(clazz); - } + HealthCheckResolver resolver = camelContext.adapt(ExtendedCamelContext.class).getHealthCheckResolver(); + answer = resolver.resolveHealthCheck(id, camelContext); } return answer; @@ -144,15 +135,8 @@ public class DefaultHealthCheckRegistry extends ServiceSupport implements Health .orElse(camelContext.getRegistry().findByTypeWithName(HealthCheckRepository.class).get(id)); if (answer == null) { // discover via classpath (try first via -health-check-repository and then id as-is) - FactoryFinder ff = camelContext.adapt(ExtendedCamelContext.class).getDefaultFactoryFinder(); - Class<? extends HealthCheckRepository> clazz = (Class<? extends HealthCheckRepository>) ff - .findOptionalClass(id + "-health-check-repository").orElse(null); - if (clazz == null) { - clazz = (Class<? extends HealthCheckRepository>) ff.findOptionalClass(id).orElse(null); - } - if (clazz != null) { - answer = camelContext.getInjector().newInstance(clazz); - } + HealthCheckResolver resolver = camelContext.adapt(ExtendedCamelContext.class).getHealthCheckResolver(); + answer = resolver.resolveHealthCheckRepository(id, camelContext); } return answer; diff --git a/core/camel-health/src/main/java/org/apache/camel/impl/health/RoutesHealthCheckRepository.java b/core/camel-health/src/main/java/org/apache/camel/impl/health/RoutesHealthCheckRepository.java index da9e794..01c91e3 100644 --- a/core/camel-health/src/main/java/org/apache/camel/impl/health/RoutesHealthCheckRepository.java +++ b/core/camel-health/src/main/java/org/apache/camel/impl/health/RoutesHealthCheckRepository.java @@ -29,15 +29,15 @@ import org.apache.camel.Route; import org.apache.camel.health.HealthCheck; import org.apache.camel.health.HealthCheckConfiguration; import org.apache.camel.health.HealthCheckRepository; -import org.apache.camel.spi.annotations.JdkService; import org.apache.camel.support.PatternHelper; /** * Repository for routes {@link HealthCheck}s. */ -@JdkService("routes-health-check-repository") +@org.apache.camel.spi.annotations.HealthCheck("routes-repository") @DeferredContextBinding public class RoutesHealthCheckRepository implements CamelContextAware, HealthCheckRepository { + private final ConcurrentMap<Route, HealthCheck> checks; private volatile CamelContext context; private Map<String, HealthCheckConfiguration> configurations; diff --git a/docs/user-manual/modules/ROOT/pages/health-check.adoc b/docs/user-manual/modules/ROOT/pages/health-check.adoc index db219e0..0b5771a 100644 --- a/docs/user-manual/modules/ROOT/pages/health-check.adoc +++ b/docs/user-manual/modules/ROOT/pages/health-check.adoc @@ -79,7 +79,7 @@ Camel supports via `camel-main` to configure health-checks from configuration fi such as Camel on Spring Boot, or Camel K. Camel will automatically enable `context`, `routes`, `consumers`, and `registry` health-checks if `camel-health` is detected on the classpath. -They are all enabled by default. However, you can configure them, for example to turn it off: +They are all enabled by default. However, you can configure them, for example to turn them off: [source,properties] ---- diff --git a/tooling/spi-annotations/src/main/java/org/apache/camel/spi/annotations/ConstantProvider.java b/tooling/spi-annotations/src/main/java/org/apache/camel/spi/annotations/ConstantProvider.java index 6c756d0..44e44bf 100644 --- a/tooling/spi-annotations/src/main/java/org/apache/camel/spi/annotations/ConstantProvider.java +++ b/tooling/spi-annotations/src/main/java/org/apache/camel/spi/annotations/ConstantProvider.java @@ -22,6 +22,9 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Internal annotation to mark a class as having constant fields for the source code generator. + */ @Retention(RetentionPolicy.RUNTIME) @Documented @Target({ ElementType.TYPE }) diff --git a/core/camel-api/src/generated/java/org/apache/camel/spi/annotations/ConstantProvider.java b/tooling/spi-annotations/src/main/java/org/apache/camel/spi/annotations/HealthCheck.java similarity index 72% copy from core/camel-api/src/generated/java/org/apache/camel/spi/annotations/ConstantProvider.java copy to tooling/spi-annotations/src/main/java/org/apache/camel/spi/annotations/HealthCheck.java index 6c756d0..7a539f4 100644 --- a/core/camel-api/src/generated/java/org/apache/camel/spi/annotations/ConstantProvider.java +++ b/tooling/spi-annotations/src/main/java/org/apache/camel/spi/annotations/HealthCheck.java @@ -22,11 +22,21 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Marks a class as a custom health-check or health-check repository. + */ @Retention(RetentionPolicy.RUNTIME) @Documented @Target({ ElementType.TYPE }) -public @interface ConstantProvider { +@ServiceFactory("health-check") +public @interface HealthCheck { + /** + * The ID of the health check. + * + * Use <tt>-check</tt> as prefix for health checks, and use <tt>-repository</tt> as prefix for health-check repository. + * For example to use myfoo as the ID for a health-check, then set this value as <tt>myfoo-check</tt>. + */ String value(); }