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();
 
 }

Reply via email to