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 330346fbd9ea771d247f1dae6a039e64096fab6a Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Tue Nov 30 15:00:27 2021 +0100 CAMEL-15133: camel-health - Resolve health-checks from classpath and make it friendlier to provide custom health checks. --- .../apache/camel/health/HealthCheckRegistry.java | 6 ++ .../camel/impl/engine/AbstractCamelContext.java | 16 +++++- .../FastAnnotationTypeConverterLoader.java | 1 + .../impl/health/DefaultHealthCheckRegistry.java | 23 ++++++++ .../impl/health/DefaultHealthChecksLoader.java | 65 ++++++++++++++++++++++ 5 files changed, 109 insertions(+), 2 deletions(-) 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 c2b3523..9f28f33 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 @@ -115,4 +115,10 @@ public interface HealthCheckRegistry extends CamelContextAware, StaticService, I * Returns a sequential {@code Stream} with the known {@link HealthCheck} as its source. */ Stream<HealthCheck> stream(); + + /** + * Loads custom health checks by scanning classpath. + */ + void loadHealthChecks(); + } 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 e1a1498..0c3b44b 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 @@ -2737,7 +2737,19 @@ public abstract class AbstractCamelContext extends BaseService // ensure additional type converters is loaded if (loadTypeConverters && typeConverter instanceof AnnotationScanTypeConverters) { + StartupStep step2 = startupStepRecorder.beginStep(CamelContext.class, null, "Scan TypeConverters"); ((AnnotationScanTypeConverters) typeConverter).scanTypeConverters(); + startupStepRecorder.endStep(step2); + } + + // ensure additional health checks is loaded + if (loadHealthChecks) { + StartupStep step3 = startupStepRecorder.beginStep(CamelContext.class, null, "Scan HealthChecks"); + HealthCheckRegistry hcr = getExtension(HealthCheckRegistry.class); + if (hcr != null) { + hcr.loadHealthChecks(); + } + startupStepRecorder.endStep(step3); } // custom properties may use property placeholders so resolve those @@ -2821,7 +2833,7 @@ public abstract class AbstractCamelContext extends BaseService bindDataFormats(); - // start components + // init components ServiceHelper.initService(components.values()); // create route definitions from route templates if we have any sources @@ -2881,7 +2893,7 @@ public abstract class AbstractCamelContext extends BaseService @Override protected void doStart() throws Exception { if (firstStartDone) { - // its not good practice to reset a camel context + // its not good practice resetting a camel context LOG.warn("Starting CamelContext: {} after the context has been stopped is not recommended", getName()); } StartupStep step = startupStepRecorder.beginStep(CamelContext.class, getName(), "Start CamelContext"); diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/converter/FastAnnotationTypeConverterLoader.java b/core/camel-base/src/main/java/org/apache/camel/impl/converter/FastAnnotationTypeConverterLoader.java index 7614f73..6c08c48 100644 --- a/core/camel-base/src/main/java/org/apache/camel/impl/converter/FastAnnotationTypeConverterLoader.java +++ b/core/camel-base/src/main/java/org/apache/camel/impl/converter/FastAnnotationTypeConverterLoader.java @@ -19,6 +19,7 @@ package org.apache.camel.impl.converter; import org.apache.camel.Converter; import org.apache.camel.spi.PackageScanClassResolver; +@Deprecated public final class FastAnnotationTypeConverterLoader extends AnnotationTypeConverterLoader { public FastAnnotationTypeConverterLoader(PackageScanClassResolver resolver) { 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 7d2140b..3f23821 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 @@ -16,6 +16,7 @@ */ package org.apache.camel.impl.health; +import java.util.Collection; import java.util.Optional; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; @@ -31,6 +32,8 @@ import org.apache.camel.health.HealthCheckRepository; import org.apache.camel.health.HealthCheckResolver; import org.apache.camel.support.service.ServiceSupport; import org.apache.camel.util.ObjectHelper; +import org.apache.camel.util.StopWatch; +import org.apache.camel.util.TimeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,6 +50,7 @@ public class DefaultHealthCheckRegistry extends ServiceSupport implements Health private final Set<HealthCheckRepository> repositories; private CamelContext camelContext; private boolean enabled = true; + private volatile boolean loadHealthChecksDone; public DefaultHealthCheckRegistry() { this(null); @@ -223,6 +227,25 @@ public class DefaultHealthCheckRegistry extends ServiceSupport implements Health return Stream.empty(); } + @Override + public void loadHealthChecks() { + StopWatch watch = new StopWatch(); + + if (!loadHealthChecksDone) { + loadHealthChecksDone = true; + + DefaultHealthChecksLoader loader = new DefaultHealthChecksLoader( + camelContext.adapt(ExtendedCamelContext.class).getPackageScanResourceResolver()); + Collection<HealthCheck> col = loader.loadHealthChecks(); + + // report how many health checks we have loaded + if (col.size() > 0) { + String time = TimeUtils.printDuration(watch.taken()); + LOG.info("Health checks (scanned: {}) loaded in {}", col.size(), time); + } + } + } + private void checkIfAccepted(Object obj) { boolean accept = obj instanceof HealthCheck || obj instanceof HealthCheckRepository; if (!accept) { diff --git a/core/camel-health/src/main/java/org/apache/camel/impl/health/DefaultHealthChecksLoader.java b/core/camel-health/src/main/java/org/apache/camel/impl/health/DefaultHealthChecksLoader.java new file mode 100644 index 0000000..750fd6e --- /dev/null +++ b/core/camel-health/src/main/java/org/apache/camel/impl/health/DefaultHealthChecksLoader.java @@ -0,0 +1,65 @@ +/* + * 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 java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import org.apache.camel.health.HealthCheck; +import org.apache.camel.spi.PackageScanResourceResolver; +import org.apache.camel.spi.Resource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * To load custom health-checks by classpath scanning. + */ +public class DefaultHealthChecksLoader { + + public static final String META_INF_SERVICES = "META-INF/services/org/apache/camel/health-check"; + private static final Logger LOG = LoggerFactory.getLogger(DefaultHealthChecksLoader.class); + private static final Charset UTF8 = Charset.forName("UTF-8"); + + protected PackageScanResourceResolver resolver; + protected Set<Class<?>> visitedClasses = new HashSet<>(); + protected Set<String> visitedURIs = new HashSet<>(); + + public DefaultHealthChecksLoader(PackageScanResourceResolver resolver) { + this.resolver = resolver; + } + + public Collection<HealthCheck> loadHealthChecks() { + Collection<HealthCheck> answer = new ArrayList<>(); + + LOG.trace("Searching for {} health checks", META_INF_SERVICES); + + try { + Collection<Resource> resources = resolver.findResources(META_INF_SERVICES + "/*-check"); + for (Resource resource : resources) { + System.out.println(resource); + } + } catch (Exception e) { + // ignore + } + + return answer; + } + +}