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