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 4a231fecd3c3 CAMEL-25373: camel-rest - the unresolved path parameter
warning comes back once a minute, and names an exchange property (#27426)
4a231fecd3c3 is described below
commit 4a231fecd3c3289619611c4e8cf8ef561c3a623e
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue Oct 6 11:23:25 2026 +0200
CAMEL-25373: camel-rest - the unresolved path parameter warning comes back
once a minute, and names an exchange property (#27426)
CAMEL-25373: camel-rest - the unresolved path parameter warning comes back
once a minute, and names an exchange property of that name
Claude-Session: https://claude.ai/code/session_01STT6whBgK1AqsSsUKrnE8m
Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
---
.../apache/camel/component/rest/RestProducer.java | 38 ++++++++++++++++++----
.../rest/RestProducerUnresolvedPathWarnTest.java | 32 +++++++++++++++++-
2 files changed, 62 insertions(+), 8 deletions(-)
diff --git
a/components/camel-rest/src/main/java/org/apache/camel/component/rest/RestProducer.java
b/components/camel-rest/src/main/java/org/apache/camel/component/rest/RestProducer.java
index f668f3de9fcf..8bc734d81506 100644
---
a/components/camel-rest/src/main/java/org/apache/camel/component/rest/RestProducer.java
+++
b/components/camel-rest/src/main/java/org/apache/camel/component/rest/RestProducer.java
@@ -23,7 +23,6 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
-import java.util.Set;
import java.util.StringJoiner;
import java.util.concurrent.ConcurrentHashMap;
@@ -58,8 +57,14 @@ public class RestProducer extends DefaultAsyncProducer {
private static final Logger LOG =
LoggerFactory.getLogger(RestProducer.class);
- /** The path parameters already warned about, so a misconfigured route
says it once and not per message. */
- private final Set<String> warnedParameters = ConcurrentHashMap.newKeySet();
+ /**
+ * When each path parameter was last warned about: a misconfigured route
says it once a minute, not per message, and
+ * not only once, as a storm of failures that follows would push a single
warning out of sight (CAMEL-25373).
+ */
+ private final Map<String, Long> warnedParameters = new
ConcurrentHashMap<>();
+
+ /** How often the warning about one path parameter is repeated while it
stays unresolved; visible for tests. */
+ long warnIntervalMillis = 60_000;
private final CamelContext camelContext;
private final RestConfiguration configuration;
@@ -180,11 +185,17 @@ public class RestProducer extends DefaultAsyncProducer {
// the request is sent with the placeholder still in the path,
and the service answers 404 for a
// path that holds a {name}, so say which parameter had no
value (CAMEL-24986)
String unresolved = firstPlaceholder(resolvedUriTemplate);
- if (unresolved != null && warnedParameters.add(unresolved)) {
+ if (unresolved != null && shouldWarn(unresolved)) {
+ // a value kept as an exchange property is the usual
mistake: the path is filled from headers and
+ // variables only
+ String property = exchange.getProperty(unresolved) != null
+ ? " There is an exchange property " + unresolved +
", but a path parameter is read from a"
+ + " header or a variable, not from a property:
use setHeader."
+ : "";
LOG.warn("The path parameter {{}} of {} has no value: set
the header {}, or an exchange variable"
- + " of that name, before the call. The request is
sent with {{}} in the path, which the"
- + " service is unlikely to answer. This is logged
once per parameter.",
- unresolved, resolvedUriTemplate, unresolved,
unresolved);
+ + " of that name, before the call.{} The request
is sent with {{}} in the path, which the"
+ + " service is unlikely to answer. This is logged
at most once a minute per parameter.",
+ unresolved, resolvedUriTemplate, unresolved,
property, unresolved);
}
}
}
@@ -240,6 +251,19 @@ public class RestProducer extends DefaultAsyncProducer {
}
}
+ /** Whether to warn about the parameter now: the first time, and again
once the interval has passed. */
+ private boolean shouldWarn(String parameter) {
+ long now = System.currentTimeMillis();
+ Long last = warnedParameters.get(parameter);
+ if (last != null && now - last < warnIntervalMillis) {
+ return false;
+ }
+ // two threads may both pass the check above; only the one that
updates the entry warns
+ return last == null
+ ? warnedParameters.putIfAbsent(parameter, now) == null
+ : warnedParameters.replace(parameter, last, now);
+ }
+
/**
* The name of the first {@code {name}} left in the template, or null when
every one of them was resolved. Only a
* name counts, so a uri that holds braces for another reason is left
alone (CAMEL-24986).
diff --git
a/core/camel-core/src/test/java/org/apache/camel/component/rest/RestProducerUnresolvedPathWarnTest.java
b/core/camel-core/src/test/java/org/apache/camel/component/rest/RestProducerUnresolvedPathWarnTest.java
index 4811f470810e..58eb91989745 100644
---
a/core/camel-core/src/test/java/org/apache/camel/component/rest/RestProducerUnresolvedPathWarnTest.java
+++
b/core/camel-core/src/test/java/org/apache/camel/component/rest/RestProducerUnresolvedPathWarnTest.java
@@ -35,7 +35,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* A path parameter with no value leaves its {name} in the uri and the service
answers 404 for it, so the producer says
- * which parameter it was. The request is still sent, as it was before
(CAMEL-24986).
+ * which parameter it was. The request is still sent, as it was before
(CAMEL-24986). The warning is repeated once a
+ * minute, and names an exchange property of the same name (CAMEL-25373).
*/
public class RestProducerUnresolvedPathWarnTest {
@@ -126,4 +127,33 @@ public class RestProducerUnresolvedPathWarnTest {
assertEquals("http://localhost/warnnone/1",
exchange.getIn().getHeader(Exchange.REST_HTTP_URI));
assertTrue(warningsFor("warnnone").isEmpty(), warnings.toString());
}
+
+ /** CAMEL-25373: the value kept as an exchange property is named, as that
is the usual mistake. */
+ @Test
+ public void testSaysWhenTheValueIsAnExchangeProperty() throws Exception {
+ RestProducer producer = createProducer("rest:get:warnprop/{sku}");
+ Exchange exchange = producer.createExchange();
+ exchange.setProperty("sku", "CAMEL-MUG");
+
+ producer.process(exchange);
+
+ List<String> mine = warningsFor("warnprop");
+ assertEquals(1, mine.size(), warnings.toString());
+ assertTrue(mine.get(0).contains("There is an exchange property sku"),
mine.get(0));
+ assertTrue(mine.get(0).contains("use setHeader"), mine.get(0));
+ }
+
+ /** CAMEL-25373: the warning comes back once the interval has passed, so a
storm of failures does not bury it. */
+ @Test
+ public void testSaysItAgainAfterTheInterval() throws Exception {
+ RestProducer producer = createProducer("rest:get:warnagain/{id}");
+ producer.warnIntervalMillis = 0;
+
+ for (int i = 0; i < 3; i++) {
+ Exchange exchange = producer.createExchange();
+ producer.process(exchange);
+ }
+
+ assertEquals(3, warningsFor("warnagain").size(), warnings.toString());
+ }
}