Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1328,7 +1328,7 @@ Java::
[source,java]
----
from("direct:start")
.to("mongodb:mongoBean?database=${mongodb.database}&collection=${mongodb.collection}&operation=getDbStats")
.to("mongodb:mongoBean?database={{mongodb.database}}&collection={{mongodb.collection}}&operation=getDbStats")
.to("direct:result");
----

Expand All @@ -1339,7 +1339,7 @@ XML::
<route>
<from uri="direct:start" />
<!-- using bean 'mongoBean' defined above -->
<to uri="mongodb:mongoBean?database=${mongodb.database}&amp;collection=${mongodb.collection}&amp;operation=getDbStats" />
<to uri="mongodb:mongoBean?database={{mongodb.database}}&amp;collection={{mongodb.collection}}&amp;operation=getDbStats" />
<to uri="direct:result" />
</route>
----
Expand All @@ -1355,8 +1355,8 @@ YAML::
- to:
uri: mongodb:mongoBean
parameters:
database: "${mongodb.database}"
collection: "${mongodb.collection}"
database: "{{mongodb.database}}"
collection: "{{mongodb.collection}}"
operation: getDbStats
- to:
uri: direct:result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ Java::
[source,java]
----
from("direct:start")
.to("mongodb-gridfs:mongoBean?database=${mongodb.database}&operation=findOne")
.to("mongodb-gridfs:mongoBean?database={{mongodb.database}}&operation=findOne")
.to("direct:result");
----

Expand All @@ -150,7 +150,7 @@ XML::
<route>
<from uri="direct:start" />
<!-- using bean 'mongoBean' defined above -->
<to uri="mongodb-gridfs:mongoBean?database=${mongodb.database}&amp;operation=findOne" />
<to uri="mongodb-gridfs:mongoBean?database={{mongodb.database}}&amp;operation=findOne" />
<to uri="direct:result" />
</route>
----
Expand All @@ -166,7 +166,7 @@ YAML::
- to:
uri: mongodb-gridfs:mongoBean
parameters:
database: "${mongodb.database}"
database: "{{mongodb.database}}"
operation: findOne
- to:
uri: direct:result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,21 +86,21 @@ Java::
+
[source,java]
----
from("direct")
from("direct:start")
.setHeader("MyHeader", simple("{{spring-config:custom.property}}"))
.to("log");
.to("log:info");
----

XML::
+
[source,xml]
----
<route>
<from uri="direct"/>
<from uri="direct:start"/>
<setHeader name="MyHeader">
<simple>{{spring-config:custom.property}}</simple>
</setHeader>
<to uri="log"/>
<to uri="log:info"/>
</route>
----

Expand All @@ -110,13 +110,13 @@ YAML::
----
- route:
from:
uri: direct
uri: direct:start
steps:
- setHeader:
name: MyHeader
simple: "{{spring-config:custom.property}}"
- to:
uri: log
uri: log:info
----
====

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ Java::
[source,java]
----
from("direct:start")
.to("mongodb-gridfs:mongoBean?database=${mongodb.database}&operation=findOne")
.to("mongodb-gridfs:mongoBean?database={{mongodb.database}}&operation=findOne")
.to("direct:result");
----

Expand All @@ -150,7 +150,7 @@ XML::
<route>
<from uri="direct:start" />
<!-- using bean 'mongoBean' defined above -->
<to uri="mongodb-gridfs:mongoBean?database=${mongodb.database}&amp;operation=findOne" />
<to uri="mongodb-gridfs:mongoBean?database={{mongodb.database}}&amp;operation=findOne" />
<to uri="direct:result" />
</route>
----
Expand All @@ -166,7 +166,7 @@ YAML::
- to:
uri: mongodb-gridfs:mongoBean
parameters:
database: "${mongodb.database}"
database: "{{mongodb.database}}"
operation: findOne
- to:
uri: direct:result
Expand Down
8 changes: 4 additions & 4 deletions components/camel-mongodb/src/main/docs/mongodb-component.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1328,7 +1328,7 @@ Java::
[source,java]
----
from("direct:start")
.to("mongodb:mongoBean?database=${mongodb.database}&collection=${mongodb.collection}&operation=getDbStats")
.to("mongodb:mongoBean?database={{mongodb.database}}&collection={{mongodb.collection}}&operation=getDbStats")
.to("direct:result");
----

Expand All @@ -1339,7 +1339,7 @@ XML::
<route>
<from uri="direct:start" />
<!-- using bean 'mongoBean' defined above -->
<to uri="mongodb:mongoBean?database=${mongodb.database}&amp;collection=${mongodb.collection}&amp;operation=getDbStats" />
<to uri="mongodb:mongoBean?database={{mongodb.database}}&amp;collection={{mongodb.collection}}&amp;operation=getDbStats" />
<to uri="direct:result" />
</route>
----
Expand All @@ -1355,8 +1355,8 @@ YAML::
- to:
uri: mongodb:mongoBean
parameters:
database: "${mongodb.database}"
collection: "${mongodb.collection}"
database: "{{mongodb.database}}"
collection: "{{mongodb.collection}}"
operation: getDbStats
- to:
uri: direct:result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,21 +86,21 @@ Java::
+
[source,java]
----
from("direct")
from("direct:start")
.setHeader("MyHeader", simple("{{spring-config:custom.property}}"))
.to("log");
.to("log:info");
----

XML::
+
[source,xml]
----
<route>
<from uri="direct"/>
<from uri="direct:start"/>
<setHeader name="MyHeader">
<simple>{{spring-config:custom.property}}</simple>
</setHeader>
<to uri="log"/>
<to uri="log:info"/>
</route>
----

Expand All @@ -110,13 +110,13 @@ YAML::
----
- route:
from:
uri: direct
uri: direct:start
steps:
- setHeader:
name: MyHeader
simple: "{{spring-config:custom.property}}"
- to:
uri: log
uri: log:info
----
====

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,11 @@ same `camel_` names by both MCP servers, `camel mcp` and `camel tui --mcp`: `cam
`camel_catalog_find`, `camel_validate_source`, `camel_get_files`, `camel_write_file`, `camel_run`,
`camel_control`, `camel_get_log`, `camel_get_errors`, `camel_eval_expression` and `camel_error_diagnose`.

The `camel_write_file` tool, when an integration of the project is selected and runs in dev mode, waits up to
eight seconds for the reload of the written file and answers with its outcome (`reload.status` reloaded, failed
with the cause and the validator's report, properties, or unknown), so an agent does not go on with a route that
did not load. A write with no selected integration answers as before.

In the TUI MCP server the tools `tui_catalog_doc`, `tui_validate_source`, `tui_write_file`, `tui_get_files`,
`tui_control`, `tui_get_log`, `tui_get_errors` and `tui_eval_expression` were renamed to the `camel_` names
above; the `tui_` prefix is now reserved for the tools that only make sense in front of the screen. Update
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,9 @@ public static JsonObject validate(ToolContext ctx, Path dir, String file, String
return result;
}

/** How long a write waits for the running integration's reload record before answering without it. */
static final long RELOAD_WAIT_MILLIS = 8000;

/** Writes a file after validating it, as {@code camel_write_file} does; no confirmation is asked here. */
public static JsonObject writeFile(ToolContext ctx, Path dir, String file, String content, boolean validate) {
Path path = resolveFile(dir, file);
Expand All @@ -378,6 +381,16 @@ public static JsonObject writeFile(ToolContext ctx, Path dir, String file, Strin
return result;
}
}
// the reload of a running integration is reported in the answer (CAMEL-24859): the reload records newer
// than the ones before the write
String processName = null;
String sinceKey = null;
boolean watch = ctx.hasProcess() && SourceValidator.isValidatableFile(file);
if (watch) {
RuntimeHelper.ProcessInfo p = RuntimeHelper.findProcess(Long.toString(ctx.pid()));
processName = p != null ? p.name() : null;
sinceKey = ReloadOutcome.latestReloadKey(ReloadOutcome.records(ctx.pid(), processName));
}
try {
Files.createDirectories(path.getParent());
Files.writeString(path, content, StandardCharsets.UTF_8);
Expand All @@ -390,8 +403,21 @@ public static JsonObject writeFile(ToolContext ctx, Path dir, String file, Strin
result.put("directory", dir.toString());
result.put("lines", content.isEmpty() ? 0 : (int) content.lines().count());
result.put("bytes", content.getBytes(StandardCharsets.UTF_8).length);
result.put("message", "An integration running the file in dev mode reloads it now; otherwise restart the"
+ " integration for the change to take effect.");
if (watch) {
JsonObject reload = ReloadOutcome.await(ctx.pid(), processName, sinceKey, RELOAD_WAIT_MILLIS);
result.put("reload", reload);
String status = reload.getString("status");
result.put("message", switch (status) {
case "reloaded" -> "The running integration reloaded the file.";
case "properties" -> "The running integration reloaded the properties.";
case "failed" -> "The running integration FAILED to reload the file, the route is not running; fix the"
+ " content and write again (see reload.message).";
default -> "Written; " + reload.getString("message");
});
} else {
result.put("message", "An integration running the file in dev mode reloads it now; otherwise restart the"
+ " integration for the change to take effect.");
}
return result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,60 @@ public static Set<String> declaredBeans(String content) {
return names;
}

/** A bean property line: key: value, under properties: of a bean. */
private static final Pattern PROPERTY_LINE = Pattern.compile("^\\s*([A-Za-z_][\\w.-]*):\\s*(.+?)\\s*$");

/**
* properties: {start: ${order.first-number}} on a bean: a Simple expression, which a bean property is not; the
* placeholder is {{order.first-number}}. The runtime fails to bind the property ("Error binding property
* (start=${order.first-number})"), and camel validate said nothing (CAMEL-24857).
*/
static List<String> validateBeanPropertyPlaceholders(String content) {
List<String> msgs = new ArrayList<>();
String[] lines = content.split("\n", -1);
int blockIndent = -1;
int propsIndent = -1;
for (int i = 0; i < lines.length; i++) {
String line = lines[i];
if (line.isBlank() || line.trim().startsWith("#")) {
continue;
}
String trimmed = line.trim();
int indent = countLeadingSpaces(line);
if (blockIndent >= 0 && indent <= blockIndent) {
blockIndent = -1;
propsIndent = -1;
}
if (blockIndent < 0) {
if (trimmed.equals("- beans:") || trimmed.equals("beans:")) {
blockIndent = indent;
}
continue;
}
if (propsIndent >= 0 && indent <= propsIndent) {
propsIndent = -1;
}
if (trimmed.equals("properties:")) {
propsIndent = indent;
continue;
}
if (propsIndent < 0) {
continue;
}
Matcher m = PROPERTY_LINE.matcher(line);
if (m.find()) {
String value = unquote(m.group(2));
if (YamlLines.isPropertyKeyInSimpleSyntax(value)) {
String key = YamlLines.propertyKeyOf(value);
msgs.add("Line " + (i + 1) + ": " + m.group(1) + ": " + value + " is a Simple expression, which a bean"
+ " property is not evaluated as: a property placeholder is written {{key}}, so "
+ m.group(1) + ": \"{{" + key + "}}\"");
}
}
}
return msgs;
}

/**
* Bean references in the YAML that nothing declares, each with how to declare it. A reference that is a
* {@code #class:}, {@code #type:} or {@code #bean:} value, a property placeholder, or a class name is left alone.
Expand All @@ -169,6 +223,7 @@ public static List<String> validateYamlBeanRefs(String content, BeanDeclarations
if (content == null) {
return msgs;
}
msgs.addAll(validateBeanPropertyPlaceholders(content));
Set<String> declared = new HashSet<>(declaredBeans(content));
if (external != null) {
declared.addAll(external.names());
Expand Down
Loading
Loading