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
The following commit(s) were added to refs/heads/main by this push:
new 20bbc3c8d8eb CAMEL-25101: camel-main - The "Property not
auto-configured" warnings are never logged (#27004)
20bbc3c8d8eb is described below
commit 20bbc3c8d8ebb6e71cca95163de9ef4cf5ff314f
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Sep 28 23:20:49 2026 +0200
CAMEL-25101: camel-main - The "Property not auto-configured" warnings are
never logged (#27004)
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Signed-off-by: Claus Ibsen <[email protected]>
---
.../org/apache/camel/main/BaseMainSupport.java | 239 +++++++++------------
.../main/MainNotAutoConfiguredWarningTest.java | 114 ++++++++++
.../apache/camel/util/BaseOrderedProperties.java | 186 ++++++++++++++++
.../apache/camel/util/OrderedPropertiesTest.java | 45 ++++
.../ROOT/pages/camel-4x-upgrade-guide-4_23.adoc | 12 ++
5 files changed, 455 insertions(+), 141 deletions(-)
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 a213084e7f8b..9af1ceb78a3e 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
@@ -941,8 +941,8 @@ public abstract class BaseMainSupport extends BaseService {
// log which options was not set
if (!properties.isEmpty()) {
properties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured:
camel.startupcondition.{}={} on object: {}", k, v,
- mainConfigurationProperties.startupCondition());
+ LOG.warn("Property not auto-configured:
camel.startupcondition.{}={} on object: {}", k,
+ maskValue(camelContext, k, v),
mainConfigurationProperties.startupCondition());
});
}
@@ -1366,11 +1366,7 @@ public abstract class BaseMainSupport extends
BaseService {
setVaultProperties(camelContext, vaultProperties,
mainConfigurationProperties.isAutoConfigurationFailFast(),
autoConfiguredProperties);
}
- if (!vaultProperties.isEmpty()) {
- vaultProperties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured: camel.vault.{}={}", k,
v);
- });
- }
+ warnNotAutoConfigured(camelContext, "camel.vault.", vaultProperties);
}
protected void doInitFileConfigurations(CamelContext camelContext,
MainConfigurationProperties config) throws Exception {
@@ -1662,6 +1658,8 @@ public abstract class BaseMainSupport extends BaseService
{
if (!variableProperties.isEmpty()) {
LOG.debug("Auto-configuring Variables from loaded properties: {}",
variableProperties.size());
MainSupportModelConfigurer.setVariableProperties(camelContext,
variableProperties, autoConfiguredProperties);
+ // the variables have been set
+ variableProperties.clear();
}
// create beans first as they may be used later
if (!beansProperties.isEmpty()) {
@@ -1733,22 +1731,26 @@ public abstract class BaseMainSupport extends
BaseService {
mainConfigurationProperties.isAutoConfigurationFailFast(),
autoConfiguredProperties);
}
+ // only one tracing service is used (the first that is enabled)
+ boolean tracing = false;
if (!otelProperties.isEmpty() ||
mainConfigurationProperties.hasOtelConfiguration()) {
LOG.debug("Auto-configuring OpenTelemetry from loaded properties:
{}", otelProperties.size());
- setOtelProperties(camelContext, otelProperties,
mainConfigurationProperties.isAutoConfigurationFailFast(),
+ tracing = setOtelProperties(camelContext, otelProperties,
+ mainConfigurationProperties.isAutoConfigurationFailFast(),
autoConfiguredProperties);
- } else if (!otel2Properties.isEmpty() ||
mainConfigurationProperties.hasOtel2Configuration()) {
+ }
+ if (!tracing && (!otel2Properties.isEmpty() ||
mainConfigurationProperties.hasOtel2Configuration())) {
LOG.debug("Auto-configuring OpenTelemetry 2 from loaded
properties: {}", otel2Properties.size());
- setOtel2Properties(camelContext, otel2Properties,
mainConfigurationProperties.isAutoConfigurationFailFast(),
+ tracing = setOtel2Properties(camelContext, otel2Properties,
+ mainConfigurationProperties.isAutoConfigurationFailFast(),
+ autoConfiguredProperties);
+ }
+ // Attempt to fallback to Telemetry simple only if no other tracing
service is found
+ if (!tracing && (!telemetryDevProperties.isEmpty() ||
mainConfigurationProperties.hasTelemetryDevConfiguration())) {
+ LOG.debug("Auto-configuring TelemetryDev from loaded properties:
{}", telemetryDevProperties.size());
+ setTelemetryDevProperties(camelContext, telemetryDevProperties,
+ mainConfigurationProperties.isAutoConfigurationFailFast(),
autoConfiguredProperties);
- } else {
- // Attempt to fallback to Telemetry simple only if no other
tracing service is found
- if (!telemetryDevProperties.isEmpty() ||
mainConfigurationProperties.hasTelemetryDevConfiguration()) {
- LOG.debug("Auto-configuring TelemetryDev from loaded
properties: {}", telemetryDevProperties.size());
- setTelemetryDevProperties(camelContext, telemetryDevProperties,
-
mainConfigurationProperties.isAutoConfigurationFailFast(),
- autoConfiguredProperties);
- }
}
if (!metricsProperties.isEmpty() ||
mainConfigurationProperties.hasMetricsConfiguration()) {
LOG.debug("Auto-configuring Micrometer metrics from loaded
properties: {}", metricsProperties.size());
@@ -1808,119 +1810,31 @@ public abstract class BaseMainSupport extends
BaseService {
autoConfiguredProperties, resilience4jProperties,
faultToleranceProperties);
// log which options was not set
- if (!variableProperties.isEmpty()) {
- variableProperties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured: camel.variable.{}={}",
k, v);
- });
- }
- if (!beansProperties.isEmpty()) {
- beansProperties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured: camel.beans.{}={}", k,
v);
- });
- }
- if (!contextProperties.isEmpty()) {
- contextProperties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured: camel.context.{}={}",
k, v);
- });
- }
- if (!resilience4jProperties.isEmpty()) {
- resilience4jProperties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured:
camel.resilience4j.{}={}", k, v);
- });
- }
- if (!faultToleranceProperties.isEmpty()) {
- faultToleranceProperties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured:
camel.faulttolerance.{}={}", k, v);
- });
- }
- if (!restProperties.isEmpty()) {
- restProperties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured: camel.rest.{}={}", k,
v);
- });
- }
- if (!threadPoolProperties.isEmpty()) {
- threadPoolProperties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured:
camel.threadpool.{}={}", k, v);
- });
- }
- if (!healthProperties.isEmpty()) {
- healthProperties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured: camel.health.{}={}",
k, v);
- });
- }
- if (!securityProperties.isEmpty()) {
- securityProperties.forEach((k, v) -> LOG.warn("Property not
auto-configured: camel.security.{}={}", k, v));
- }
- if (!sslProperties.isEmpty()) {
- sslProperties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured: camel.ssl.{}={}", k,
v);
- });
- }
- if (!debuggerProperties.isEmpty()) {
- debuggerProperties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured: camel.debug.{}={}", k,
v);
- });
- }
- if (!routeControllerProperties.isEmpty()) {
- routeControllerProperties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured:
camel.routeController.{}={}", k, v);
- });
- }
- if (!errorRegistryProperties.isEmpty()) {
- errorRegistryProperties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured:
camel.errorRegistry.{}={}", k, v);
- });
- }
- if (!aiObservabilityProperties.isEmpty()) {
- aiObservabilityProperties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured:
camel.aiObservability.{}={}", k, v);
- });
- }
- if (!devConsoleProperties.isEmpty()) {
- devConsoleProperties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured:
camel.devConsole.{}={}", k, v);
- });
- }
- if (!routeTemplateProperties.isEmpty()) {
- routeTemplateProperties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured:
camel.routetemplate.{}={}", k, v);
- });
- }
- if (!lraProperties.isEmpty()) {
- lraProperties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured: camel.lra.{}={}", k,
v);
- });
- }
- if (!otelProperties.isEmpty()) {
- otelProperties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured:
camel.opentelemetry.{}={}", k, v);
- });
- }
- if (!otel2Properties.isEmpty()) {
- otel2Properties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured:
camel.opentelemetry2.{}={}", k, v);
- });
- }
- if (!telemetryDevProperties.isEmpty()) {
- telemetryDevProperties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured:
camel.telemetryDev.{}={}", k, v);
- });
- }
- if (!httpServerProperties.isEmpty()) {
- httpServerProperties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured: camel.server.{}={}",
k, v);
- });
- }
- if (!httpManagementServerProperties.isEmpty()) {
- httpManagementServerProperties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured:
camel.management.{}={}", k, v);
- });
- }
- if (!mdcProperties.isEmpty()) {
- mdcProperties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured: camel.mdc.{}={}", k,
v);
- });
- }
+ warnNotAutoConfigured(camelContext, "camel.variable.",
variableProperties);
+ warnNotAutoConfigured(camelContext, "camel.beans.", beansProperties);
+ warnNotAutoConfigured(camelContext, "camel.context.",
contextProperties);
+ warnNotAutoConfigured(camelContext, "camel.resilience4j.",
resilience4jProperties);
+ warnNotAutoConfigured(camelContext, "camel.faulttolerance.",
faultToleranceProperties);
+ warnNotAutoConfigured(camelContext, "camel.rest.", restProperties);
+ warnNotAutoConfigured(camelContext, "camel.threadpool.",
threadPoolProperties);
+ warnNotAutoConfigured(camelContext, "camel.health.", healthProperties);
+ warnNotAutoConfigured(camelContext, "camel.security.",
securityProperties);
+ warnNotAutoConfigured(camelContext, "camel.ssl.", sslProperties);
+ warnNotAutoConfigured(camelContext, "camel.debug.",
debuggerProperties);
+ warnNotAutoConfigured(camelContext, "camel.routeController.",
routeControllerProperties);
+ warnNotAutoConfigured(camelContext, "camel.errorRegistry.",
errorRegistryProperties);
+ warnNotAutoConfigured(camelContext, "camel.aiObservability.",
aiObservabilityProperties);
+ warnNotAutoConfigured(camelContext, "camel.devConsole.",
devConsoleProperties);
+ warnNotAutoConfigured(camelContext, "camel.routetemplate.",
routeTemplateProperties);
+ warnNotAutoConfigured(camelContext, "camel.lra.", lraProperties);
+ warnNotAutoConfigured(camelContext, "camel.opentelemetry.",
otelProperties);
+ warnNotAutoConfigured(camelContext, "camel.opentelemetry2.",
otel2Properties);
+ warnNotAutoConfigured(camelContext, "camel.telemetryDev.",
telemetryDevProperties);
+ warnNotAutoConfigured(camelContext, "camel.server.",
httpServerProperties);
+ warnNotAutoConfigured(camelContext, "camel.management.",
httpManagementServerProperties);
+ warnNotAutoConfigured(camelContext, "camel.mdc.", mdcProperties);
+ warnNotAutoConfigured(camelContext, "camel.metrics.",
metricsProperties);
+ warnNotAutoConfigured(camelContext, "camel.trace.", tracerProperties);
// and call after all properties are set
DefaultConfigurationConfigurer.afterPropertiesSet(camelContext);
@@ -2058,6 +1972,17 @@ public abstract class BaseMainSupport extends
BaseService {
}
}
+ private static void warnNotAutoConfigured(
+ CamelContext camelContext, String prefix,
OrderedLocationProperties properties) {
+ properties.forEach(
+ (k, v) -> LOG.warn("Property not auto-configured: {}{}={}",
prefix, k, maskValue(camelContext, k, v)));
+ }
+
+ private static Object maskValue(CamelContext camelContext, Object key,
Object value) {
+ // the values of sensitive options are masked
+ return MainHelper.containsSensitive(camelContext, key.toString(),
value) ? "xxxxxx" : value;
+ }
+
/**
* Adds the options configured using the Java API (the options that are
not the default value), which are not
* already configured as properties (properties take precedence).
@@ -2079,7 +2004,7 @@ public abstract class BaseMainSupport extends BaseService
{
}
}
- private void setLraCheckProperties(
+ private boolean setLraCheckProperties(
CamelContext camelContext, OrderedLocationProperties lraProperties,
boolean failIfNotSet, OrderedLocationProperties
autoConfiguredProperties)
throws Exception {
@@ -2109,6 +2034,11 @@ public abstract class BaseMainSupport extends
BaseService {
// add as service so saga can be active
camelContext.addService(css, true, true);
}
+ if (!enabled) {
+ // the service is disabled so its options are not used
+ lraProperties.clear();
+ }
+ return enabled;
}
private void setClusterServiceProperties(
@@ -2156,7 +2086,7 @@ public abstract class BaseMainSupport extends BaseService
{
camelContext, factoryKey, CamelClusterService.class, "camel-"
+ type);
}
- private void setOtelProperties(
+ private boolean setOtelProperties(
CamelContext camelContext, OrderedLocationProperties
otelProperties,
boolean failIfNotSet, OrderedLocationProperties
autoConfiguredProperties)
throws Exception {
@@ -2189,9 +2119,14 @@ public abstract class BaseMainSupport extends
BaseService {
camelContext.addService(otel, true, true);
}
}
+ if (!enabled) {
+ // the service is disabled so its options are not used
+ otelProperties.clear();
+ }
+ return enabled;
}
- private void setOtel2Properties(
+ private boolean setOtel2Properties(
CamelContext camelContext, OrderedLocationProperties
otel2Properties,
boolean failIfNotSet, OrderedLocationProperties
autoConfiguredProperties)
throws Exception {
@@ -2211,9 +2146,14 @@ public abstract class BaseMainSupport extends
BaseService {
camelContext.addService(otel, true, true);
}
}
+ if (!enabled) {
+ // the service is disabled so its options are not used
+ otel2Properties.clear();
+ }
+ return enabled;
}
- private void setMdcProperties(
+ private boolean setMdcProperties(
CamelContext camelContext, OrderedLocationProperties mdcProperties,
boolean failIfNotSet, OrderedLocationProperties
autoConfiguredProperties)
throws Exception {
@@ -2233,9 +2173,14 @@ public abstract class BaseMainSupport extends
BaseService {
camelContext.addService(mdc, true, true);
}
}
+ if (!enabled) {
+ // the service is disabled so its options are not used
+ mdcProperties.clear();
+ }
+ return enabled;
}
- private void setTelemetryDevProperties(
+ private boolean setTelemetryDevProperties(
CamelContext camelContext, OrderedLocationProperties
telemetryDevProperties,
boolean failIfNotSet, OrderedLocationProperties
autoConfiguredProperties)
throws Exception {
@@ -2256,9 +2201,14 @@ public abstract class BaseMainSupport extends
BaseService {
camelContext.addService(telemetryDev, true, true);
}
}
+ if (!enabled) {
+ // the service is disabled so its options are not used
+ telemetryDevProperties.clear();
+ }
+ return enabled;
}
- private void setMetricsProperties(
+ private boolean setMetricsProperties(
CamelContext camelContext, OrderedLocationProperties
metricsProperties,
boolean failIfNotSet, OrderedLocationProperties
autoConfiguredProperties)
throws Exception {
@@ -2291,6 +2241,11 @@ public abstract class BaseMainSupport extends
BaseService {
camelContext.addService(micrometer, true, true);
}
}
+ if (!enabled) {
+ // the service is disabled so its options are not used
+ metricsProperties.clear();
+ }
+ return enabled;
}
private void setDevConsoleProperties(
@@ -2981,8 +2936,8 @@ public abstract class BaseMainSupport extends BaseService
{
// log which options was not set
if (!properties.isEmpty()) {
properties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured:
camel.component.properties.{}={} on object: {}", k, v,
- camelContext.getPropertiesComponent());
+ LOG.warn("Property not auto-configured:
camel.component.properties.{}={} on object: {}", k,
+ maskValue(camelContext, k, v),
camelContext.getPropertiesComponent());
});
}
}
@@ -3043,7 +2998,8 @@ public abstract class BaseMainSupport extends BaseService
{
// log which options was not set
if (!properties.isEmpty()) {
properties.forEach((k, v) -> {
- LOG.warn("Property not auto-configured: camel.main.{}={} on
bean: {}", k, v, config);
+ LOG.warn("Property not auto-configured: camel.main.{}={} on
bean: {}", k, maskValue(camelContext, k, v),
+ config);
});
}
}
@@ -3214,7 +3170,8 @@ public abstract class BaseMainSupport extends BaseService
{
PropertyOptionKey pok = entry.getKey();
OrderedLocationProperties values = entry.getValue();
values.forEach((k, v) -> {
- String stringValue = v != null ? v.toString() : null;
+ Object value = maskValue(camelContext, k, v);
+ String stringValue = value != null ? value.toString() :
null;
LOG.warn("Property ({}={}) not auto-configured with name:
{} on bean: {} with value: {}",
pok.getOptionPrefix() + "." + k, stringValue, k,
pok.getInstance(), stringValue);
});
diff --git
a/core/camel-main/src/test/java/org/apache/camel/main/MainNotAutoConfiguredWarningTest.java
b/core/camel-main/src/test/java/org/apache/camel/main/MainNotAutoConfiguredWarningTest.java
new file mode 100644
index 000000000000..8331a2d143ea
--- /dev/null
+++
b/core/camel-main/src/test/java/org/apache/camel/main/MainNotAutoConfiguredWarningTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.main;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.appender.AbstractAppender;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.LoggerConfig;
+import org.apache.logging.log4j.core.config.Property;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class MainNotAutoConfiguredWarningTest {
+
+ private static final String LOGGER = BaseMainSupport.class.getName();
+
+ private final List<String> warnings = new CopyOnWriteArrayList<>();
+ private AbstractAppender appender;
+
+ @BeforeEach
+ public void addAppender() {
+ appender = new AbstractAppender("MainNotAutoConfiguredWarningTest",
null, null, true, Property.EMPTY_ARRAY) {
+ @Override
+ public void append(LogEvent event) {
+ if (event.getLevel() == Level.WARN) {
+ warnings.add(event.getMessage().getFormattedMessage());
+ }
+ }
+ };
+ appender.start();
+ LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
+ Configuration config = ctx.getConfiguration();
+ LoggerConfig loggerConfig = new LoggerConfig(LOGGER, Level.WARN, true);
+ loggerConfig.addAppender(appender, Level.WARN, null);
+ config.addLogger(LOGGER, loggerConfig);
+ ctx.updateLoggers();
+ }
+
+ @AfterEach
+ public void removeAppender() {
+ LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
+ ctx.getConfiguration().removeLogger(LOGGER);
+ ctx.updateLoggers();
+ appender.stop();
+ }
+
+ private List<String> notAutoConfigured() {
+ return warnings.stream().filter(w -> w.contains("not
auto-configured")).toList();
+ }
+
+ @Test
+ public void testTypoIsLogged() {
+ Main main = new Main();
+ main.configure().withAutoConfigurationFailFast(false);
+ main.addProperty("camel.rest.contxtPath", "/api");
+ main.addProperty("camel.rest.password", "S3cr3t");
+ main.start();
+ try {
+ List<String> list = notAutoConfigured();
+ assertEquals(2, list.size(), list.toString());
+ assertTrue(list.stream().anyMatch(w ->
w.contains("camel.rest.contxtPath=/api")), list.toString());
+ // the value of a sensitive option is masked
+ assertTrue(list.stream().anyMatch(w ->
w.contains("camel.rest.password=xxxxxx")), list.toString());
+ assertTrue(list.stream().noneMatch(w -> w.contains("S3cr3t")),
list.toString());
+ } finally {
+ main.stop();
+ }
+ }
+
+ @Test
+ public void testNoWarningsForValidConfiguration() {
+ Main main = new Main();
+ main.configure().withAutoConfigurationFailFast(false);
+ main.addProperty("camel.variable.greeting", "Hello");
+ main.addProperty("camel.variable.global.foo", "123");
+ main.addProperty("camel.rest.contextPath", "/api");
+ main.addProperty("camel.lra.enabled", "false");
+ main.addProperty("camel.lra.coordinatorUrl", "http://localhost:8080");
+ main.addProperty("camel.opentelemetry.enabled", "false");
+ main.addProperty("camel.opentelemetry.instrumentationName", "camel");
+ main.start();
+ try {
+ List<String> list = notAutoConfigured();
+ assertTrue(list.isEmpty(), list.toString());
+ assertEquals("Hello",
main.getCamelContext().getVariable("greeting"));
+ } finally {
+ main.stop();
+ }
+ }
+}
diff --git
a/core/camel-util/src/main/java/org/apache/camel/util/BaseOrderedProperties.java
b/core/camel-util/src/main/java/org/apache/camel/util/BaseOrderedProperties.java
index 92dc44fc9e7d..f533ee212a9f 100644
---
a/core/camel-util/src/main/java/org/apache/camel/util/BaseOrderedProperties.java
+++
b/core/camel-util/src/main/java/org/apache/camel/util/BaseOrderedProperties.java
@@ -21,12 +21,17 @@ import java.util.Collection;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
/**
* Base class for ordered properties implementations.
@@ -187,6 +192,187 @@ abstract class BaseOrderedProperties extends Properties {
return new ArrayList<>(map.values());
}
+ @Override
+ public Enumeration<Object> elements() {
+ lock.lock();
+ try {
+ return new Vector<>(map.values()).elements();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ public void forEach(BiConsumer<? super Object, ? super Object> action) {
+ List<Map.Entry<String, Object>> entries;
+ lock.lock();
+ try {
+ // iterate a copy so the action can change the properties
+ entries = new ArrayList<>(map.entrySet());
+ } finally {
+ lock.unlock();
+ }
+ for (Map.Entry<String, Object> entry : entries) {
+ action.accept(entry.getKey(), entry.getValue());
+ }
+ }
+
+ @Override
+ public Object getOrDefault(Object key, Object defaultValue) {
+ Object answer = get(key);
+ return answer != null ? answer : defaultValue;
+ }
+
+ @Override
+ public Object putIfAbsent(Object key, Object value) {
+ lock.lock();
+ try {
+ Object answer = get(key);
+ if (answer == null) {
+ put(key, value);
+ }
+ return answer;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ public boolean remove(Object key, Object value) {
+ lock.lock();
+ try {
+ if (containsKey(key) && Objects.equals(get(key), value)) {
+ remove(key);
+ return true;
+ }
+ return false;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ public Object replace(Object key, Object value) {
+ lock.lock();
+ try {
+ return containsKey(key) ? put(key, value) : null;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ public boolean replace(Object key, Object oldValue, Object newValue) {
+ lock.lock();
+ try {
+ if (containsKey(key) && Objects.equals(get(key), oldValue)) {
+ put(key, newValue);
+ return true;
+ }
+ return false;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ public void replaceAll(BiFunction<? super Object, ? super Object, ?>
function) {
+ lock.lock();
+ try {
+ for (String key : new ArrayList<>(map.keySet())) {
+ put(key, function.apply(key, get(key)));
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ public Object computeIfAbsent(Object key, Function<? super Object, ?>
mappingFunction) {
+ lock.lock();
+ try {
+ Object answer = get(key);
+ if (answer == null) {
+ answer = mappingFunction.apply(key);
+ if (answer != null) {
+ put(key, answer);
+ }
+ }
+ return answer;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ public Object computeIfPresent(Object key, BiFunction<? super Object, ?
super Object, ?> remappingFunction) {
+ lock.lock();
+ try {
+ Object old = get(key);
+ if (old == null) {
+ return null;
+ }
+ Object answer = remappingFunction.apply(key, old);
+ if (answer == null) {
+ remove(key);
+ } else {
+ put(key, answer);
+ }
+ return answer;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ public Object compute(Object key, BiFunction<? super Object, ? super
Object, ?> remappingFunction) {
+ lock.lock();
+ try {
+ Object answer = remappingFunction.apply(key, get(key));
+ if (answer == null) {
+ remove(key);
+ } else {
+ put(key, answer);
+ }
+ return answer;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ public Object merge(Object key, Object value, BiFunction<? super Object, ?
super Object, ?> remappingFunction) {
+ lock.lock();
+ try {
+ Object old = get(key);
+ Object answer = old == null ? value : remappingFunction.apply(old,
value);
+ if (answer == null) {
+ remove(key);
+ } else {
+ put(key, answer);
+ }
+ return answer;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o instanceof BaseOrderedProperties other) {
+ return map.equals(other.map);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return map.hashCode();
+ }
+
@Override
public String toString() {
lock.lock();
diff --git
a/core/camel-util/src/test/java/org/apache/camel/util/OrderedPropertiesTest.java
b/core/camel-util/src/test/java/org/apache/camel/util/OrderedPropertiesTest.java
index 9299f7643c42..0e4afa8bbac3 100644
---
a/core/camel-util/src/test/java/org/apache/camel/util/OrderedPropertiesTest.java
+++
b/core/camel-util/src/test/java/org/apache/camel/util/OrderedPropertiesTest.java
@@ -16,13 +16,18 @@
*/
package org.apache.camel.util;
+import java.util.ArrayList;
+import java.util.Enumeration;
import java.util.Iterator;
+import java.util.List;
import java.util.Properties;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class OrderedPropertiesTest {
@@ -113,4 +118,44 @@ public class OrderedPropertiesTest {
assertFalse(prop.containsKey("foo"));
}
+ @Test
+ public void testMapMethods() {
+ OrderedLocationProperties prop = new OrderedLocationProperties();
+ prop.put("app.properties", "b", "1");
+ prop.put("app.properties", "a", "2");
+
+ // forEach iterates the properties (in order)
+ List<Object> keys = new ArrayList<>();
+ prop.forEach((k, v) -> keys.add(k));
+ assertEquals(List.of("b", "a"), keys);
+
+ assertEquals("1", prop.getOrDefault("b", "x"));
+ assertEquals("x", prop.getOrDefault("c", "x"));
+
+ assertEquals("1", prop.putIfAbsent("b", "3"));
+ assertNull(prop.putIfAbsent("c", "3"));
+ assertEquals("3", prop.get("c"));
+
+ assertEquals("33", prop.compute("c", (k, v) -> v + "3"));
+ assertEquals("4", prop.computeIfAbsent("d", k -> "4"));
+ assertEquals("44", prop.merge("d", "4", (a, b) -> a + "" + b));
+ assertEquals("2", prop.replace("a", "22"));
+ assertTrue(prop.replace("a", "22", "222"));
+ assertEquals("222", prop.get("a"));
+ assertTrue(prop.remove("d", "44"));
+ assertFalse(prop.containsKey("d"));
+
+ List<Object> values = new ArrayList<>();
+ Enumeration<Object> e = prop.elements();
+ while (e.hasMoreElements()) {
+ values.add(e.nextElement());
+ }
+ assertEquals(List.of("1", "222", "33"), values);
+
+ OrderedLocationProperties other = new OrderedLocationProperties();
+ other.put("b", "1");
+ assertNotEquals(prop, other);
+ assertEquals(prop, prop);
+ }
+
}
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
index 2fff5abd625c..4a9d13e2e3ea 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
@@ -3045,6 +3045,18 @@ The accessors changed accordingly:
The fluent builder `ParamDefinition.required(Boolean)` is unchanged, and a
`required(String)` overload
was added for placeholders. Routes written in XML, YAML or the Java DSL do not
need any change.
+=== camel-main - properties that are not auto-configured are logged
+
+When `camel.main.autoConfigurationFailFast=false`, camel-main now logs a WARN
for each `camel.*` property that could
+not be applied (such as a typo in the name of an option), for example
+`Property not auto-configured: camel.rest.contxtPath=/api`. These warnings
were never logged before. The values of
+sensitive options (such as passwords) are masked. With fail-fast (the default)
an unknown property fails the startup
+as before.
+
+When `camel.opentelemetry.*` properties are configured but OpenTelemetry is
disabled (`camel.opentelemetry.enabled=false`),
+the `camel.opentelemetry2.*` or `camel.telemetryDev.*` properties are now
used. Previously they were ignored whenever
+any `camel.opentelemetry.*` property was configured.
+
=== camel-seda - stopping a suspended route does not wait for its pending
messages
Stopping a suspended SEDA route, or stopping the CamelContext while such a
route is suspended, no longer waits for the