This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch secret
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 9532a317c68f39c1ad61e1e0f528143256054a45
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed Sep 7 12:55:34 2022 +0200

    CAMEL-18454: Allow to enable secret refresh from vault. (AWS)
---
 .../apache/camel/periodic-task/aws-secret-refresh  |  2 +
 .../vault/CloudTrailReloadTriggerTask.java         | 78 +++++++++++++++++-----
 .../apache/camel/spi/annotations/PeriodicTask.java | 24 +++----
 .../org/apache/camel/ExtendedCamelContext.java     | 22 ++++++
 .../org/apache/camel/spi/PeriodTaskResolver.java   | 45 +++++++++++++
 .../org/apache/camel/spi/PeriodTaskScheduler.java  | 30 +++++++++
 .../camel/impl/engine/AbstractCamelContext.java    | 41 ++++++++++++
 .../impl/engine/DefaultPeriodTaskResolver.java     | 41 ++++++++++++
 .../impl/engine/DefaultPeriodTaskScheduler.java    | 68 +++++++++++++++++++
 .../camel/impl/engine/SimpleCamelContext.java      | 15 +++++
 .../camel/impl/ExtendedCamelContextConfigurer.java | 12 ++++
 .../camel/impl/lw/LightweightCamelContext.java     | 23 +++++++
 .../impl/lw/LightweightRuntimeCamelContext.java    | 26 ++++++++
 .../camel/impl/engine/PeriodTaskSchedulerTest.java | 50 ++++++++++++++
 .../org/apache/camel/main/BaseMainSupport.java     | 29 ++++++++
 .../apache/camel/spi/annotations/PeriodicTask.java | 24 +++----
 16 files changed, 480 insertions(+), 50 deletions(-)

diff --git 
a/components/camel-aws/camel-aws-secrets-manager/src/generated/resources/META-INF/services/org/apache/camel/periodic-task/aws-secret-refresh
 
b/components/camel-aws/camel-aws-secrets-manager/src/generated/resources/META-INF/services/org/apache/camel/periodic-task/aws-secret-refresh
new file mode 100644
index 00000000000..88ae1a62a4a
--- /dev/null
+++ 
b/components/camel-aws/camel-aws-secrets-manager/src/generated/resources/META-INF/services/org/apache/camel/periodic-task/aws-secret-refresh
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.aws.secretsmanager.vault.CloudTrailReloadTriggerTask
diff --git 
a/components/camel-aws/camel-aws-secrets-manager/src/main/java/org/apache/camel/component/aws/secretsmanager/vault/CloudTrailReloadTriggerTask.java
 
b/components/camel-aws/camel-aws-secrets-manager/src/main/java/org/apache/camel/component/aws/secretsmanager/vault/CloudTrailReloadTriggerTask.java
index fbfb01e1860..ccd8332196f 100644
--- 
a/components/camel-aws/camel-aws-secrets-manager/src/main/java/org/apache/camel/component/aws/secretsmanager/vault/CloudTrailReloadTriggerTask.java
+++ 
b/components/camel-aws/camel-aws-secrets-manager/src/main/java/org/apache/camel/component/aws/secretsmanager/vault/CloudTrailReloadTriggerTask.java
@@ -20,8 +20,12 @@ import java.time.Instant;
 import java.util.List;
 
 import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
 import org.apache.camel.spi.ContextReloadStrategy;
+import org.apache.camel.spi.annotations.PeriodicTask;
 import org.apache.camel.support.PatternHelper;
+import org.apache.camel.support.service.ServiceSupport;
+import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
@@ -42,40 +46,73 @@ import 
software.amazon.awssdk.services.cloudtrail.model.Resource;
  * Period task which checks if AWS secrets has been updated and
  * can trigger Camel to be reloaded.
  */
-public class CloudTrailReloadTriggerTask implements Runnable {
+@PeriodicTask("aws-secret-refresh")
+public class CloudTrailReloadTriggerTask extends ServiceSupport implements 
CamelContextAware, Runnable {
 
-    // TODO: extends ServiceSupport
-    // TODO: doStart to create CloudTrailClient
-    // TODO: doStop to cleanup if needed
     // TODO: support ENV like SecretsManagerPropertiesFunction
 
     private static final Logger LOG = 
LoggerFactory.getLogger(CloudTrailReloadTriggerTask.class);
     private static final String SECRETSMANAGER_AMAZONAWS_COM = 
"secretsmanager.amazonaws.com";
 
-    private final CamelContext context;
-    private final String secrets;
+    private CamelContext camelContext;
+    private CloudTrailClient cloudTrailClient;
+    private String secrets;
     private volatile Instant lastTime;
 
-    public CloudTrailReloadTriggerTask(CamelContext context, String secrets) {
-        this.context = context;
-        this.secrets = secrets;
+    public CloudTrailReloadTriggerTask() {
     }
 
     @Override
-    public void run() {
-        boolean triggerReloading = false;
+    public CamelContext getCamelContext() {
+        return camelContext;
+    }
+
+    @Override
+    public void setCamelContext(CamelContext camelContext) {
+        this.camelContext = camelContext;
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+
+        secrets = camelContext.getVaultConfiguration().aws().getSecrets();
+        if (ObjectHelper.isEmpty(secrets)) {
+            throw new IllegalArgumentException("Secrets must be configured on 
AWS vault configuration");
+        }
+
         CloudTrailClientBuilder cloudTrailClientBuilder;
-        Region regionValue = 
Region.of(context.getVaultConfiguration().aws().getRegion());
-        if 
(context.getVaultConfiguration().aws().isDefaultCredentialsProvider()) {
+        Region regionValue = 
Region.of(camelContext.getVaultConfiguration().aws().getRegion());
+        if 
(camelContext.getVaultConfiguration().aws().isDefaultCredentialsProvider()) {
             cloudTrailClientBuilder = CloudTrailClient.builder()
                     .region(regionValue)
                     .credentialsProvider(ProfileCredentialsProvider.create());
         } else {
-            AwsBasicCredentials cred = 
AwsBasicCredentials.create(context.getVaultConfiguration().aws().getAccessKey(),
-                    context.getVaultConfiguration().aws().getSecretKey());
+            AwsBasicCredentials cred = 
AwsBasicCredentials.create(camelContext.getVaultConfiguration().aws().getAccessKey(),
+                    camelContext.getVaultConfiguration().aws().getSecretKey());
             cloudTrailClientBuilder = 
CloudTrailClient.builder().credentialsProvider(StaticCredentialsProvider.create(cred));
         }
-        CloudTrailClient cloudTrailClient = cloudTrailClientBuilder.build();
+        cloudTrailClient = cloudTrailClientBuilder.build();
+    }
+
+    @Override
+    protected void doShutdown() throws Exception {
+        super.doShutdown();
+
+        if (cloudTrailClient != null) {
+            try {
+                cloudTrailClient.close();
+            } catch (Exception e) {
+                // ignore
+            }
+            cloudTrailClient = null;
+        }
+    }
+
+    @Override
+    public void run() {
+        boolean triggerReloading = false;
+
         try {
             LookupEventsRequest.Builder eventsRequestBuilder = 
LookupEventsRequest.builder()
                     
.maxResults(100).lookupAttributes(LookupAttribute.builder().attributeKey(LookupAttributeKey.EVENT_SOURCE)
@@ -115,10 +152,10 @@ public class CloudTrailReloadTriggerTask implements 
Runnable {
         }
 
         if (triggerReloading) {
-            ContextReloadStrategy reload = 
context.hasService(ContextReloadStrategy.class);
+            ContextReloadStrategy reload = 
camelContext.hasService(ContextReloadStrategy.class);
             if (reload != null) {
                 // trigger reload
-                reload.onReload(context.getName());
+                reload.onReload(camelContext.getName());
             }
         }
     }
@@ -132,4 +169,9 @@ public class CloudTrailReloadTriggerTask implements 
Runnable {
         }
         return false;
     }
+
+    @Override
+    public String toString() {
+        return "AWS Secrets Refresh Task";
+    }
 }
diff --git 
a/tooling/spi-annotations/src/main/java/org/apache/camel/spi/annotations/EagerClassloaded.java
 
b/core/camel-api/src/generated/java/org/apache/camel/spi/annotations/PeriodicTask.java
similarity index 62%
rename from 
tooling/spi-annotations/src/main/java/org/apache/camel/spi/annotations/EagerClassloaded.java
rename to 
core/camel-api/src/generated/java/org/apache/camel/spi/annotations/PeriodicTask.java
index 99817acd930..58390eca05c 100644
--- 
a/tooling/spi-annotations/src/main/java/org/apache/camel/spi/annotations/EagerClassloaded.java
+++ 
b/core/camel-api/src/generated/java/org/apache/camel/spi/annotations/PeriodicTask.java
@@ -16,26 +16,18 @@
  */
 package org.apache.camel.spi.annotations;
 
+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;
 
-/**
- * Marks this class to be eager loaded by the JDK classloader so the class is 
already loaded when Camel is started.
- *
- * This is intended to assist required classes that Camel always uses.
- *
- * <b>Important:</b> The class must have the following static method which 
will be invoked to force loading the class.
- * 
- * <pre>
- * public static void onClassloaded(org.slf4j.Logger log) {
- *     .. do warmup here such as logging the class name or create inner 
classes to force loading them
- *     log.trace("Loaded {}", this.getClass().getName());
- * }
- * </pre>
- */
-@Target(ElementType.TYPE)
 @Retention(RetentionPolicy.RUNTIME)
-public @interface EagerClassloaded {
+@Documented
+@Target({ ElementType.TYPE })
+@ServiceFactory("periodic-task")
+public @interface PeriodicTask {
+
+    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 2ef87502346..29f5abe5b34 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
@@ -59,6 +59,8 @@ import org.apache.camel.spi.NodeIdFactory;
 import org.apache.camel.spi.NormalizedEndpointUri;
 import org.apache.camel.spi.PackageScanClassResolver;
 import org.apache.camel.spi.PackageScanResourceResolver;
+import org.apache.camel.spi.PeriodTaskResolver;
+import org.apache.camel.spi.PeriodTaskScheduler;
 import org.apache.camel.spi.ProcessorExchangeFactory;
 import org.apache.camel.spi.ProcessorFactory;
 import org.apache.camel.spi.ReactiveExecutor;
@@ -888,4 +890,24 @@ public interface ExtendedCamelContext extends CamelContext 
{
      */
     byte getStatusPhase();
 
+    /**
+     * Gets the period task scheduler
+     */
+    PeriodTaskScheduler getPeriodTaskScheduler();
+
+    /**
+     * To use a custom period task scheduler
+     */
+    void setPeriodTaskScheduler(PeriodTaskScheduler periodTaskScheduler);
+
+    /**
+     * Gets the period task resolver
+     */
+    PeriodTaskResolver getPeriodTaskResolver();
+
+    /**
+     * To use a custom period task resolver
+     */
+    void setPeriodTaskResolver(PeriodTaskResolver periodTaskResolver);
+
 }
diff --git 
a/core/camel-api/src/main/java/org/apache/camel/spi/PeriodTaskResolver.java 
b/core/camel-api/src/main/java/org/apache/camel/spi/PeriodTaskResolver.java
new file mode 100644
index 00000000000..50ff6fdda1a
--- /dev/null
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/PeriodTaskResolver.java
@@ -0,0 +1,45 @@
+/*
+ * 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.spi;
+
+import java.util.Optional;
+
+/**
+ * Finder to find {@link org.apache.camel.spi.annotations.PeriodicTask} tasks.
+ */
+public interface PeriodTaskResolver {
+
+    String RESOURCE_PATH = "META-INF/services/org/apache/camel/periodic-task/";
+
+    /**
+     * Creates a new class instance using the key to lookup
+     *
+     * @param  key is the key to add to the path to find a text file 
containing the factory name
+     * @return     a newly created instance (if exists)
+     */
+    Optional<Object> newInstance(String key);
+
+    /**
+     * Creates a new class instance using the key to lookup
+     *
+     * @param  key  is the key to add to the path to find a text file 
containing the factory name
+     * @param  type the class type
+     * @return      a newly created instance (if exists)
+     */
+    <T> Optional<T> newInstance(String key, Class<T> type);
+
+}
diff --git 
a/core/camel-api/src/main/java/org/apache/camel/spi/PeriodTaskScheduler.java 
b/core/camel-api/src/main/java/org/apache/camel/spi/PeriodTaskScheduler.java
new file mode 100644
index 00000000000..fa7c3ad3182
--- /dev/null
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/PeriodTaskScheduler.java
@@ -0,0 +1,30 @@
+/*
+ * 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.spi;
+
+@FunctionalInterface
+public interface PeriodTaskScheduler {
+
+    /**
+     * Schedules the period task.
+     *
+     * @param task   the period task
+     * @param period the interval (approximate) in millis, between running the 
task
+     */
+    void schedulePeriodTask(Runnable task, long period);
+
+}
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 86960f4d2be..cb25e10102c 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
@@ -141,6 +141,8 @@ import org.apache.camel.spi.NodeIdFactory;
 import org.apache.camel.spi.NormalizedEndpointUri;
 import org.apache.camel.spi.PackageScanClassResolver;
 import org.apache.camel.spi.PackageScanResourceResolver;
+import org.apache.camel.spi.PeriodTaskResolver;
+import org.apache.camel.spi.PeriodTaskScheduler;
 import org.apache.camel.spi.ProcessorExchangeFactory;
 import org.apache.camel.spi.ProcessorFactory;
 import org.apache.camel.spi.PropertiesComponent;
@@ -181,6 +183,7 @@ import org.apache.camel.support.NormalizedUri;
 import org.apache.camel.support.OrderedComparator;
 import org.apache.camel.support.ProcessorEndpoint;
 import org.apache.camel.support.ResolverHelper;
+import org.apache.camel.support.TimerListenerManager;
 import org.apache.camel.support.jsse.SSLContextParameters;
 import org.apache.camel.support.service.BaseService;
 import org.apache.camel.support.service.ServiceHelper;
@@ -332,6 +335,8 @@ public abstract class AbstractCamelContext extends 
BaseService
     private volatile NodeIdFactory nodeIdFactory;
     private volatile ModelineFactory modelineFactory;
     private volatile ProcessorFactory processorFactory;
+    private volatile PeriodTaskResolver periodTaskResolver;
+    private volatile PeriodTaskScheduler periodTaskScheduler;
     private volatile InternalProcessorFactory internalProcessorFactory;
     private volatile InterceptEndpointFactory interceptEndpointFactory;
     private volatile RouteFactory routeFactory;
@@ -4205,6 +4210,38 @@ public abstract class AbstractCamelContext extends 
BaseService
         this.modelineFactory = doAddService(modelineFactory);
     }
 
+    @Override
+    public PeriodTaskResolver getPeriodTaskResolver() {
+        if (periodTaskResolver == null) {
+            synchronized (lock) {
+                if (periodTaskResolver == null) {
+                    setPeriodTaskResolver(createPeriodTaskResolver());
+                }
+            }
+        }
+        return periodTaskResolver;
+    }
+
+    @Override
+    public void setPeriodTaskResolver(PeriodTaskResolver periodTaskResolver) {
+        this.periodTaskResolver = doAddService(periodTaskResolver);
+    }
+
+    public PeriodTaskScheduler getPeriodTaskScheduler() {
+        if (periodTaskScheduler == null) {
+            synchronized (lock) {
+                if (periodTaskScheduler == null) {
+                    setPeriodTaskScheduler(createPeriodTaskScheduler());
+                }
+            }
+        }
+        return periodTaskScheduler;
+    }
+
+    public void setPeriodTaskScheduler(PeriodTaskScheduler 
periodTaskScheduler) {
+        this.periodTaskScheduler = doAddService(periodTaskScheduler);
+    }
+
     @Override
     public ManagementStrategy getManagementStrategy() {
         return managementStrategy;
@@ -5300,6 +5337,10 @@ public abstract class AbstractCamelContext extends 
BaseService
 
     protected abstract ModelineFactory createModelineFactory();
 
+    protected abstract PeriodTaskResolver createPeriodTaskResolver();
+
+    protected abstract PeriodTaskScheduler createPeriodTaskScheduler();
+
     protected abstract FactoryFinderResolver createFactoryFinderResolver();
 
     protected abstract ClassResolver createClassResolver();
diff --git 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultPeriodTaskResolver.java
 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultPeriodTaskResolver.java
new file mode 100644
index 00000000000..3c7cce5f90e
--- /dev/null
+++ 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultPeriodTaskResolver.java
@@ -0,0 +1,41 @@
+/*
+ * 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.spi.FactoryFinder;
+import org.apache.camel.spi.PeriodTaskResolver;
+
+import java.util.Optional;
+
+public class DefaultPeriodTaskResolver implements PeriodTaskResolver {
+
+    private final FactoryFinder finder;
+
+    public DefaultPeriodTaskResolver(FactoryFinder finder) {
+        this.finder = finder;
+    }
+
+    @Override
+    public Optional<Object> newInstance(String key) {
+        return finder.newInstance(key);
+    }
+
+    @Override
+    public <T> Optional<T> newInstance(String key, Class<T> type) {
+        return finder.newInstance(key, type);
+    }
+}
diff --git 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultPeriodTaskScheduler.java
 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultPeriodTaskScheduler.java
new file mode 100644
index 00000000000..6903766332c
--- /dev/null
+++ 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultPeriodTaskScheduler.java
@@ -0,0 +1,68 @@
+/*
+ * 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.TimerListener;
+import org.apache.camel.spi.PeriodTaskScheduler;
+import org.apache.camel.support.TimerListenerManager;
+import org.apache.camel.util.StopWatch;
+
+/**
+ * A {@link PeriodTaskScheduler} that schedules generic tasks from
+ * custom components that are defined with the {@link 
org.apache.camel.spi.annotations.PeriodicTask} annotation.
+ */
+public final class DefaultPeriodTaskScheduler extends TimerListenerManager 
implements PeriodTaskScheduler {
+
+    @Override
+    public void schedulePeriodTask(Runnable task, long period) {
+        addTimerListener(new TaskWrapper(task, period));
+    }
+
+    @Override
+    public void addTimerListener(TimerListener listener) {
+        if (listener instanceof TaskWrapper) {
+            super.addTimerListener(listener);
+        } else {
+            throw new IllegalArgumentException("Use the addPeriodTask method");
+        }
+    }
+
+    private static final class TaskWrapper implements TimerListener {
+
+        private final StopWatch watch = new StopWatch();
+        private final Runnable task;
+        private final long period;
+
+        public TaskWrapper(Runnable task, long period) {
+            this.task = task;
+            this.period = period;
+        }
+
+        @Override
+        public void onTimer() {
+            if (watch.taken() > period) {
+                watch.restart();
+                task.run();
+            }
+        }
+
+        @Override
+        public String toString() {
+            return task.toString();
+        }
+    }
+}
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 81ec3100073..690a87baced 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
@@ -66,6 +66,8 @@ import org.apache.camel.spi.ModelineFactory;
 import org.apache.camel.spi.NodeIdFactory;
 import org.apache.camel.spi.PackageScanClassResolver;
 import org.apache.camel.spi.PackageScanResourceResolver;
+import org.apache.camel.spi.PeriodTaskResolver;
+import org.apache.camel.spi.PeriodTaskScheduler;
 import org.apache.camel.spi.ProcessorExchangeFactory;
 import org.apache.camel.spi.ProcessorFactory;
 import org.apache.camel.spi.PropertiesComponent;
@@ -257,6 +259,19 @@ public class SimpleCamelContext extends 
AbstractCamelContext {
         }
     }
 
+    @Override
+    protected PeriodTaskResolver createPeriodTaskResolver() {
+        // we need a factory finder
+        FactoryFinder finder = getFactoryFinderResolver()
+                .resolveBootstrapFactoryFinder(getClassResolver(), 
PeriodTaskResolver.RESOURCE_PATH);
+        return new DefaultPeriodTaskResolver(finder);
+    }
+
+    @Override
+    protected PeriodTaskScheduler createPeriodTaskScheduler() {
+        return new DefaultPeriodTaskScheduler();
+    }
+
     @Override
     protected FactoryFinderResolver createFactoryFinderResolver() {
         return new DefaultFactoryFinderResolver();
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 c7f81dc3c0e..66046dfa7b7 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
@@ -145,6 +145,10 @@ public class ExtendedCamelContextConfigurer extends 
org.apache.camel.support.com
         case "PackageScanClassResolver": 
target.setPackageScanClassResolver(property(camelContext, 
org.apache.camel.spi.PackageScanClassResolver.class, value)); return true;
         case "packagescanresourceresolver":
         case "PackageScanResourceResolver": 
target.setPackageScanResourceResolver(property(camelContext, 
org.apache.camel.spi.PackageScanResourceResolver.class, value)); return true;
+        case "periodtaskresolver":
+        case "PeriodTaskResolver": 
target.setPeriodTaskResolver(property(camelContext, 
org.apache.camel.spi.PeriodTaskResolver.class, value)); return true;
+        case "periodtaskscheduler":
+        case "PeriodTaskScheduler": 
target.setPeriodTaskScheduler(property(camelContext, 
org.apache.camel.spi.PeriodTaskScheduler.class, value)); return true;
         case "processorexchangefactory":
         case "ProcessorExchangeFactory": 
target.setProcessorExchangeFactory(property(camelContext, 
org.apache.camel.spi.ProcessorExchangeFactory.class, value)); return true;
         case "processorfactory":
@@ -352,6 +356,10 @@ public class ExtendedCamelContextConfigurer extends 
org.apache.camel.support.com
         case "PackageScanClassResolver": return 
org.apache.camel.spi.PackageScanClassResolver.class;
         case "packagescanresourceresolver":
         case "PackageScanResourceResolver": return 
org.apache.camel.spi.PackageScanResourceResolver.class;
+        case "periodtaskresolver":
+        case "PeriodTaskResolver": return 
org.apache.camel.spi.PeriodTaskResolver.class;
+        case "periodtaskscheduler":
+        case "PeriodTaskScheduler": return 
org.apache.camel.spi.PeriodTaskScheduler.class;
         case "processorexchangefactory":
         case "ProcessorExchangeFactory": return 
org.apache.camel.spi.ProcessorExchangeFactory.class;
         case "processorfactory":
@@ -560,6 +568,10 @@ public class ExtendedCamelContextConfigurer extends 
org.apache.camel.support.com
         case "PackageScanClassResolver": return 
target.getPackageScanClassResolver();
         case "packagescanresourceresolver":
         case "PackageScanResourceResolver": return 
target.getPackageScanResourceResolver();
+        case "periodtaskresolver":
+        case "PeriodTaskResolver": return target.getPeriodTaskResolver();
+        case "periodtaskscheduler":
+        case "PeriodTaskScheduler": return target.getPeriodTaskScheduler();
         case "processorexchangefactory":
         case "ProcessorExchangeFactory": return 
target.getProcessorExchangeFactory();
         case "processorfactory":
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 f877d319b2f..30e22f79638 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
@@ -122,6 +122,8 @@ import org.apache.camel.spi.NodeIdFactory;
 import org.apache.camel.spi.NormalizedEndpointUri;
 import org.apache.camel.spi.PackageScanClassResolver;
 import org.apache.camel.spi.PackageScanResourceResolver;
+import org.apache.camel.spi.PeriodTaskResolver;
+import org.apache.camel.spi.PeriodTaskScheduler;
 import org.apache.camel.spi.ProcessorExchangeFactory;
 import org.apache.camel.spi.ProcessorFactory;
 import org.apache.camel.spi.PropertiesComponent;
@@ -2106,6 +2108,27 @@ public class LightweightCamelContext implements 
ExtendedCamelContext, CatalogCam
         return getModelCamelContext().getModelReifierFactory();
     }
 
+    @Override
+    public PeriodTaskScheduler getPeriodTaskScheduler() {
+        return getExtendedCamelContext().getPeriodTaskScheduler();
+    }
+
+    @Override
+    public void setPeriodTaskScheduler(PeriodTaskScheduler 
periodTaskScheduler) {
+        getExtendedCamelContext().setPeriodTaskScheduler(periodTaskScheduler);
+
+    }
+
+    @Override
+    public PeriodTaskResolver getPeriodTaskResolver() {
+        return getExtendedCamelContext().getPeriodTaskResolver();
+    }
+
+    @Override
+    public void setPeriodTaskResolver(PeriodTaskResolver periodTaskResolver) {
+        getExtendedCamelContext().setPeriodTaskResolver(periodTaskResolver);
+    }
+
     @Override
     public void setModelReifierFactory(ModelReifierFactory 
modelReifierFactory) {
         getModelCamelContext().setModelReifierFactory(modelReifierFactory);
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 38fa50f34d8..7f81221c925 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
@@ -117,6 +117,8 @@ import org.apache.camel.spi.NodeIdFactory;
 import org.apache.camel.spi.NormalizedEndpointUri;
 import org.apache.camel.spi.PackageScanClassResolver;
 import org.apache.camel.spi.PackageScanResourceResolver;
+import org.apache.camel.spi.PeriodTaskResolver;
+import org.apache.camel.spi.PeriodTaskScheduler;
 import org.apache.camel.spi.ProcessorExchangeFactory;
 import org.apache.camel.spi.ProcessorFactory;
 import org.apache.camel.spi.PropertiesComponent;
@@ -197,6 +199,8 @@ public class LightweightRuntimeCamelContext implements 
ExtendedCamelContext, Cat
     private final ProcessorFactory processorFactory;
     private final InternalProcessorFactory internalProcessorFactory;
     private final InflightRepository inflightRepository;
+    private final PeriodTaskResolver periodTaskResolver;
+    private final PeriodTaskScheduler periodTaskScheduler;
     private final Injector injector;
     private final ClassResolver classResolver;
     private final Map<String, String> globalOptions;
@@ -254,6 +258,8 @@ public class LightweightRuntimeCamelContext implements 
ExtendedCamelContext, Cat
         internalProcessorFactory = 
context.adapt(ExtendedCamelContext.class).getInternalProcessorFactory();
         routeController = context.getRouteController();
         inflightRepository = context.getInflightRepository();
+        periodTaskResolver = 
context.adapt(ExtendedCamelContext.class).getPeriodTaskResolver();
+        periodTaskScheduler  = 
context.adapt(ExtendedCamelContext.class).getPeriodTaskScheduler();
         globalOptions = context.getGlobalOptions();
         injector = context.getInjector();
         classResolver = context.getClassResolver();
@@ -2280,6 +2286,26 @@ public class LightweightRuntimeCamelContext implements 
ExtendedCamelContext, Cat
         throw new UnsupportedOperationException();
     }
 
+    @Override
+    public PeriodTaskResolver getPeriodTaskResolver() {
+        return periodTaskResolver;
+    }
+
+    @Override
+    public void setPeriodTaskScheduler(PeriodTaskScheduler 
periodTaskScheduler) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public PeriodTaskScheduler getPeriodTaskScheduler() {
+        return periodTaskScheduler;
+    }
+
+    @Override
+    public void setPeriodTaskResolver(PeriodTaskResolver periodTaskResolver) {
+        throw new UnsupportedOperationException();
+    }
+
     private void startService(Service service) throws Exception {
         // and register startup aware so they can be notified when
         // camel context has been started
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/impl/engine/PeriodTaskSchedulerTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/impl/engine/PeriodTaskSchedulerTest.java
new file mode 100644
index 00000000000..cc21c47dfc1
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/impl/engine/PeriodTaskSchedulerTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.ContextTestSupport;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.spi.PeriodTaskScheduler;
+import org.apache.camel.support.TimerListenerManager;
+import org.awaitility.Awaitility;
+import org.junit.jupiter.api.Test;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class PeriodTaskSchedulerTest extends ContextTestSupport {
+
+    private final AtomicInteger counter = new AtomicInteger();
+
+    @Override
+    public boolean isUseRouteBuilder() {
+        return false;
+    }
+
+    @Test
+    public void testScheduler() throws Exception {
+        PeriodTaskScheduler scheduler = 
context.adapt(ExtendedCamelContext.class).getPeriodTaskScheduler();
+        if (scheduler instanceof TimerListenerManager) {
+            // speedup unit test
+            ((TimerListenerManager) scheduler).setInterval(10);
+        }
+        scheduler.schedulePeriodTask(counter::incrementAndGet, 10);
+        context.start();
+
+        Awaitility.waitAtMost(5, TimeUnit.SECONDS).until(() -> counter.get() > 
0);
+    }
+}
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java 
b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
index 650e39b9758..7f8b9bbf61f 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
@@ -49,16 +49,20 @@ import org.apache.camel.health.HealthCheck;
 import org.apache.camel.health.HealthCheckRegistry;
 import org.apache.camel.health.HealthCheckRepository;
 import org.apache.camel.impl.event.CamelContextRoutesStartedEvent;
+import org.apache.camel.model.cloud.ServiceCallDefinitionConstants;
 import org.apache.camel.saga.CamelSagaService;
 import org.apache.camel.spi.AutowiredLifecycleStrategy;
 import org.apache.camel.spi.CamelBeanPostProcessor;
 import org.apache.camel.spi.CamelEvent;
 import org.apache.camel.spi.DataFormat;
+import org.apache.camel.spi.FactoryFinder;
 import org.apache.camel.spi.Language;
 import org.apache.camel.spi.PackageScanClassResolver;
+import org.apache.camel.spi.PeriodTaskScheduler;
 import org.apache.camel.spi.PropertiesComponent;
 import org.apache.camel.spi.RouteTemplateParameterSource;
 import org.apache.camel.spi.StartupStepRecorder;
+import org.apache.camel.spi.annotations.PeriodicTask;
 import org.apache.camel.support.CamelContextHelper;
 import org.apache.camel.support.EventNotifierSupport;
 import org.apache.camel.support.LifecycleStrategySupport;
@@ -66,12 +70,14 @@ import org.apache.camel.support.PropertyBindingSupport;
 import org.apache.camel.support.ResourceHelper;
 import org.apache.camel.support.service.BaseService;
 import org.apache.camel.support.startup.LoggingStartupStepRecorder;
+import org.apache.camel.support.task.BackgroundTask;
 import org.apache.camel.util.FileUtil;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.OrderedLocationProperties;
 import org.apache.camel.util.OrderedProperties;
 import org.apache.camel.util.SensitiveUtils;
 import org.apache.camel.util.StringHelper;
+import org.apache.camel.util.TimeUtils;
 import org.apache.camel.vault.VaultConfiguration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -384,6 +390,27 @@ public abstract class BaseMainSupport extends BaseService {
     protected void configureLifecycle(CamelContext camelContext) throws 
Exception {
     }
 
+    /**
+     * Configures security vaults such as AWS, Azure, Google and Hashicorp.
+     */
+    protected void configureVault(CamelContext camelContext) throws Exception {
+        VaultConfiguration vc = camelContext.getVaultConfiguration();
+        if (vc == null) {
+            return;
+        }
+
+        if (vc.aws().isRefreshEnabled()) {
+            Optional<Runnable> task = 
camelContext.adapt(ExtendedCamelContext.class)
+                    .getPeriodTaskResolver().newInstance("aws-secret-refresh", 
Runnable.class);
+            if (task.isPresent()) {
+                long period = vc.aws().getRefreshPeriod();
+                LOG.info("Scheduling: {} running every: {}", task, 
TimeUtils.printDuration(period, true));
+                PeriodTaskScheduler scheduler = 
getCamelContext().adapt(ExtendedCamelContext.class).getPeriodTaskScheduler();
+                scheduler.schedulePeriodTask(task.get(), period);
+            }
+        }
+    }
+
     protected void autoconfigure(CamelContext camelContext) throws Exception {
         // gathers the properties (key=value) that was auto-configured
         final OrderedLocationProperties autoConfiguredProperties = new 
OrderedLocationProperties();
@@ -626,6 +653,8 @@ public abstract class BaseMainSupport extends BaseService {
 
         configureLifecycle(camelContext);
 
+        configureVault(camelContext);
+
         if (standalone) {
             step = recorder.beginStep(BaseMainSupport.class, 
"configureRoutes", "Collect Routes");
             configureRoutes(camelContext);
diff --git 
a/core/camel-api/src/generated/java/org/apache/camel/spi/annotations/EagerClassloaded.java
 
b/tooling/spi-annotations/src/main/java/org/apache/camel/spi/annotations/PeriodicTask.java
similarity index 62%
rename from 
core/camel-api/src/generated/java/org/apache/camel/spi/annotations/EagerClassloaded.java
rename to 
tooling/spi-annotations/src/main/java/org/apache/camel/spi/annotations/PeriodicTask.java
index 99817acd930..58390eca05c 100644
--- 
a/core/camel-api/src/generated/java/org/apache/camel/spi/annotations/EagerClassloaded.java
+++ 
b/tooling/spi-annotations/src/main/java/org/apache/camel/spi/annotations/PeriodicTask.java
@@ -16,26 +16,18 @@
  */
 package org.apache.camel.spi.annotations;
 
+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;
 
-/**
- * Marks this class to be eager loaded by the JDK classloader so the class is 
already loaded when Camel is started.
- *
- * This is intended to assist required classes that Camel always uses.
- *
- * <b>Important:</b> The class must have the following static method which 
will be invoked to force loading the class.
- * 
- * <pre>
- * public static void onClassloaded(org.slf4j.Logger log) {
- *     .. do warmup here such as logging the class name or create inner 
classes to force loading them
- *     log.trace("Loaded {}", this.getClass().getName());
- * }
- * </pre>
- */
-@Target(ElementType.TYPE)
 @Retention(RetentionPolicy.RUNTIME)
-public @interface EagerClassloaded {
+@Documented
+@Target({ ElementType.TYPE })
+@ServiceFactory("periodic-task")
+public @interface PeriodicTask {
+
+    String value();
+
 }

Reply via email to