davsclaus commented on code in PR #26758:
URL: https://github.com/apache/camel/pull/26758#discussion_r4080274521
##########
dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/YamlValidator.java:
##########
@@ -668,6 +669,87 @@ void checkSimpleSyntaxInScripts(JsonNode node, NodePath
path, List<Error> errors
}
}
+ /**
+ * to: http://host/stock/${header.sku}: the endpoint of a to: is resolved
once when the route starts, so an
+ * expression in its path is never evaluated - it is sent as the text it
is, url-encoded. That is what toD: is for
+ * (CAMEL-24917).
+ * <p/>
+ * Only the path is checked, never the options after the {@code ?}: an
option such as the file component's
+ * {@code fileName=${date:now:yyyyMMdd}} is evaluated by the producer and
is correct on a plain to:.
+ */
+ void checkDynamicUri(JsonNode node, NodePath path, List<Error> errors) {
+ if (node == null) {
+ return;
+ }
+ if (node.isArray()) {
+ for (int i = 0; i < node.size(); i++) {
+ checkDynamicUri(node.get(i), path.append(i), errors);
+ }
+ return;
+ }
+ if (!node.isObject()) {
+ return;
+ }
+ var fields = node.fieldNames();
+ while (fields.hasNext()) {
+ String name = fields.next();
+ JsonNode value = node.get(name);
+ if ("to".equals(name)) {
+ String uri = null;
+ NodePath at = path.append(name);
+ if (value.isTextual()) {
+ uri = value.asText();
+ } else if (value.isObject() && value.has("uri") &&
value.get("uri").isTextual()) {
+ uri = value.get("uri").asText();
+ at = at.append("uri");
+ }
+ String expression = expressionInPath(uri);
+ if (expression != null) {
+ errors.add(Error.builder()
+ .keyword("type")
+ .instanceLocation(at)
+ .messageKey("type")
+ .format(new MessageFormat("{0}"))
+ .arguments("to: the uri holds an expression (" +
expression + ") but the endpoint of a to:"
+ + " is fixed when the route starts, so
it is sent as text: write toD: to build"
+ + " the uri for each message")
+ .build());
+ }
+ }
+ checkDynamicUri(value, path.append(name), errors);
+ }
+ }
+
+ /**
+ * The first simple expression in the path of the uri (what comes before
the options), or null when there is none.
+ */
+ private static String expressionInPath(String uri) {
+ if (uri == null) {
+ return null;
+ }
+ int scheme = uri.indexOf(':');
+ if (scheme > 0 && EVALUATED_PATH.contains(uri.substring(0, scheme))) {
+ return null;
+ }
+ String head = uri.indexOf('?') > 0 ? uri.substring(0,
uri.indexOf('?')) : uri;
+ int start = head.indexOf("${");
+ if (start < 0) {
+ return null;
+ }
+ if (start >= 2 && head.startsWith(":#", start - 2)) {
+ return null; // :#${...} is a parameter the component binds per
message, not part of the address
+ }
+ int end = head.indexOf('}', start);
+ return end > 0 ? head.substring(start, end + 1) :
head.substring(start);
+ }
+
+ /**
+ * Components that read their path as a script, a statement or a template
name and evaluate it for each message,
+ * where an expression in the path is what the component is for.
+ */
+ private static final Set<String> EVALUATED_PATH = Set.of("language",
"sql", "sql-stored", "elsql", "jdbc",
+ "spring-jdbc", "mybatis", "xquery", "xslt");
Review Comment:
Confirmed, and you are right about the reason: I put xslt and xquery in that
list on a guess, not on reading them. Both resolve their resource once when the
route starts, and a stylesheet per message is what `toD` and
`allowTemplateFromHeader` are for - so a `${...}` in their path is exactly the
mistake this check is meant to report. Same for `mybatis` and the jdbc family,
which I had also added without verifying.
The list is now the three I did read in their own producer: `language` (its
path is a script in another language), `micrometer` and `opentelemetry-metrics`
(both evaluate the metric name per message in
`AbstractMicrometerProducer.process` /
`AbstractOpenTelemetryProducer.process`). A test now locks the xslt case as
reported.
The list itself is the wrong mechanism though, so I filed CAMEL-24918: a
`@Metadata(supportSimpleExpression = true)` flag that reaches the catalog,
derived automatically for options typed `Expression` or `Predicate`, so the
validator asks the component instead of me guessing. That follow-up removes the
hardcoded pair as well.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]