gnodet commented on code in PR #27686:
URL: https://github.com/apache/camel/pull/27686#discussion_r4241616034
##########
components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/Kamelet.java:
##########
@@ -230,6 +232,63 @@ public static RouteDefinition
templateToRoute(RouteTemplateDefinition in, Map<St
throw new IllegalArgumentException("Camel route " + rid + " input
does not exist.");
}
+ // Extract advanced options for source/sink component endpoints
+ Map<String, Object> sourceOptions =
PropertiesHelper.extractProperties(parameters, "source.");
+ Map<String, Object> sinkOptions =
PropertiesHelper.extractProperties(parameters, "sink.");
+
+ // Determine Kamelet type: source Kamelets have real component as
input,
+ // sink/action Kamelets have kamelet:source as input and real
component in outputs
+ boolean isSourceKamelet =
!def.getInput().getEndpointUri().startsWith("kamelet:source")
+ &&
!def.getInput().getEndpointUri().startsWith("kamelet://source");
+
+ if (isSourceKamelet) {
+ // Source Kamelet: real component endpoint is the input
+ if (!sourceOptions.isEmpty()) {
+ try {
+ String newUri =
URISupport.appendParametersToURI(def.getInput().getUri(), sourceOptions);
+ def.getInput().setUri(newUri);
+ } catch (Exception e) {
+ throw new IllegalArgumentException(
+ "Failed to apply advanced source options to
endpoint URI: " + def.getInput().getUri(), e);
+ }
+ }
+ if (!sinkOptions.isEmpty()) {
+ throw new IllegalArgumentException(
+ "sink.* advanced options are not valid for source
Kamelets (input is '"
+ +
def.getInput().getEndpointUri() + "'). Use source.* options instead.");
+ }
+ } else {
+ // Sink/Action Kamelet: real component endpoint(s) are in outputs
+ if (!sourceOptions.isEmpty()) {
+ throw new IllegalArgumentException(
+ "source.* advanced options are not valid for
sink/action Kamelets (input is '"
+ +
def.getInput().getEndpointUri() + "'). Use sink.* options instead.");
+ }
+ if (!sinkOptions.isEmpty()) {
+ Collection<ToDefinition> outputs =
filterTypeInOutputs(def.getOutputs(), ToDefinition.class);
Review Comment:
⚠️ **`filterTypeInOutputs` only captures `ToDefinition` —
`ToDynamicDefinition` (.toD()) is silently skipped**
`filterTypeInOutputs(def.getOutputs(), ToDefinition.class)` returns only
static `<to>` nodes. If a Kamelet's output route uses `.toD(...)` (i.e.
`ToDynamicDefinition`), that endpoint is silently excluded and
`hasRealEndpoint` stays `false`, causing a misleading "no real endpoint found"
error — or, if there are also `ToDefinition` outputs, the `.toD()` endpoint is
just skipped without warning.
`ToDynamicDefinition` is a sibling class, not a subtype of `ToDefinition`,
so it won't be caught by the current call.
Consider filtering for both:
```java
Collection<ProcessorDefinition<?>> outputs = new ArrayList<>();
outputs.addAll(filterTypeInOutputs(def.getOutputs(), ToDefinition.class));
outputs.addAll(filterTypeInOutputs(def.getOutputs(),
ToDynamicDefinition.class));
```
Or use a combined predicate over `def.getOutputs()`. Either way, handle both
types consistently so dynamic-routing Kamelets aren't silently broken.
##########
components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/Kamelet.java:
##########
@@ -230,6 +232,63 @@ public static RouteDefinition
templateToRoute(RouteTemplateDefinition in, Map<St
throw new IllegalArgumentException("Camel route " + rid + " input
does not exist.");
}
+ // Extract advanced options for source/sink component endpoints
+ Map<String, Object> sourceOptions =
PropertiesHelper.extractProperties(parameters, "source.");
+ Map<String, Object> sinkOptions =
PropertiesHelper.extractProperties(parameters, "sink.");
+
+ // Determine Kamelet type: source Kamelets have real component as
input,
+ // sink/action Kamelets have kamelet:source as input and real
component in outputs
+ boolean isSourceKamelet =
!def.getInput().getEndpointUri().startsWith("kamelet:source")
+ &&
!def.getInput().getEndpointUri().startsWith("kamelet://source");
Review Comment:
💡 **`isSourceKamelet` heuristic covers only two URI prefixes**
The check handles `kamelet:source` and `kamelet://source` but misses
`kamelet:source/...` variants where a named path segment follows (e.g.
`kamelet:source/somePath`). This is low-risk in practice since Camel normalises
the URI before this point, but it's worth a comment or a stricter prefix check
(e.g. `startsWith("kamelet:source/")` or a regex) to make the intent explicit
and guard against future URI normalisation changes.
##########
components/camel-kamelet/src/main/docs/kamelet-component.adoc:
##########
@@ -163,6 +163,44 @@ The usage of this Kamelet into a Camel route is going to
be the same as any othe
WARNING: beware of any potential circular reference you may introduce when
using chain of Kamelets, in which case, the runtime will likely be idle
consuming a high amount of resources.
+=== Advanced component endpoint options
+
+Kamelets expose a defined set of parameters, but the underlying Camel
component may support additional endpoint options. You can pass these options
when using a Kamelet by prefixing them with `source.` or `sink.`, depending on
the type of Kamelet.
+
+==== Source Kamelets
+
+For source Kamelets, use the `source.` prefix to pass additional options to
the underlying source component endpoint. The prefix is removed when the
options are applied to the endpoint URI.
+
+For example:
+
+[source,java]
Review Comment:
💡 **The `/source` path segment in the example URI is unexplained**
The example `kamelet:my-source/source?source.block=true` uses
`kamelet:<templateId>/<routeId>` syntax where `/source` is the named route ID
within the template — but the docs don't explain this. A reader unfamiliar with
the Kamelet URI format will wonder whether `/source` is a literal keyword, a
component name, or something else.
Consider adding a brief note, e.g.: "The `/source` segment is the route ID
within the Kamelet template. Use the template's actual route ID here."
##########
components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletAdvancedOptionsTest.java:
##########
@@ -0,0 +1,211 @@
+/*
+ * 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.
Review Comment:
🐛 **Corrupted Apache license header**
Lines 14–15 are garbled — a sentence fragment from line 14 bled into line 15:
```
* limitations under the License. See the NOTICE file distributed with
* See the NOTICE file distributed with
```
The second half of line 14 belongs to the NOTICE sentence (which should read
"See the NOTICE file distributed with this work for additional information
regarding copyright ownership."), and line 15 is a duplicate fragment that
shouldn't exist.
Correct header:
```suggestion
* See the License for the specific language governing permissions and
* limitations under the License.
```
--
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]