davsclaus commented on code in PR #27646:
URL: https://github.com/apache/camel/pull/27646#discussion_r4236604730
##########
dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java:
##########
@@ -123,6 +123,7 @@ public void execute(String... args) {
.addSubcommand("route-dump", new CommandLine(new
CamelRouteDumpAction(this)))
.addSubcommand("route-structure", new CommandLine(new
CamelRouteStructureAction(this)))
.addSubcommand("route-topology", new CommandLine(new
CamelRouteTopologyAction(this)))
+ .addSubcommand("semantic-evaluate", new
CommandLine(new SemanticEvaluate(this)))
Review Comment:
Naming question: `camel eval expression` already evaluates against a running
integration with `--body`, `--header` and `--variable`, which are the same
sample-exchange options used here. Would `camel eval semantic` fit better than
`camel cmd semantic-evaluate`? We would get `camel eval expression` / `camel
eval semantic` side by side, and the command name would not repeat the verb.
I'm not strongly against `cmd semantic-evaluate`, but the JIRA left the names
open and they are hard to change after a release, so let's decide before merge.
##########
dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSemantic.java:
##########
@@ -0,0 +1,105 @@
+/*
+ * 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.dsl.jbang.core.commands.action;
+
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
+import org.apache.camel.util.json.Jsoner;
+import picocli.CommandLine;
+
[email protected](name = "semantic", description = "List semantic
definitions and expert contracts",
+ sortOptions = false, showDefaultValues = true)
+public class CamelSemantic extends SemanticActionCommand {
+
+ @CommandLine.Option(names = "--expert", description = "Show the operations
and parameter contract of this expert")
+ String expert;
+
+ public CamelSemantic(CamelJBangMain main) {
+ super(main);
+ }
+
+ @Override
+ protected JsonObject request() {
+ if (expert != null && expert.isBlank()) {
+ throw new IllegalArgumentException("--expert must not be blank");
+ }
+ JsonObject request = new JsonObject();
+ request.put("action", "semantic-metadata");
+ if (expert == null) {
+ request.put("overview", true);
+ } else {
+ request.put("expert", expert);
+ }
+ return request;
+ }
+
+ @Override
+ protected int printResponse(JsonObject response) {
+ if (expert != null) {
+ JsonArray operations = response.getCollection("operations");
+ if (operations == null || operations.isEmpty()) {
+ return error(3, "No operations available for semantic expert:
" + expert, null);
+ }
+ }
+ return super.printResponse(response);
+ }
+
+ @Override
+ protected void render(JsonObject response) {
+ if (expert != null) {
+ printer().println("Expert: " + expert);
+ renderOperations(response.getCollection("operations"));
+ return;
+ }
+ printer().println("Definitions:");
+ printer().println("NAME\tEXPERT\tOPERATION\tSTATE\tRESULT
TYPE\tERROR");
Review Comment:
The other `camel get` commands render tables with
`AsciiTable.getTable(AsciiTable.NO_BORDERS, ...)`. That includes `get
route-controller`, which also targets a single integration. Tab-separated
output looks out of place next to them and does not line up in a terminal.
Could this use the same `AsciiTable` and `Column` style for the definitions and
experts lists? Scripts already have `--json` as the machine-readable format, so
the text output can be laid out for people.
##########
dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/exceptionhandler/MissingPluginParameterExceptionHandler.java:
##########
@@ -33,6 +34,9 @@ public class MissingPluginParameterExceptionHandler
implements IParameterExcepti
public int handleParseException(ParameterException ex, String[] args)
throws Exception {
CommandLine cmd = ex.getCommandLine();
PrintWriter err = cmd.getErr();
+ if (cmd.getCommand() instanceof SemanticActionCommand semantic) {
Review Comment:
This is the generic parse-error handler for every command, and now it
depends on one concrete command type. A small interface, for example
`UsageErrorHandler { int usageError(String message, String[] args); }`,
implemented by `SemanticActionCommand`, would keep the handler generic. The
upcoming CAMEL-25389 work (central error handling and the exit-code contract)
could then adopt it for other commands without adding more `instanceof` checks
here.
##########
dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/SemanticEvaluate.java:
##########
@@ -0,0 +1,168 @@
+/*
+ * 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.dsl.jbang.core.commands.action;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectReader;
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.util.json.JsonObject;
+import org.apache.camel.util.json.Jsoner;
+import picocli.CommandLine;
+
[email protected](name = "semantic-evaluate", description = "Evaluate a
semantic definition or expert operation",
+ sortOptions = false, showDefaultValues = true)
+public class SemanticEvaluate extends SemanticActionCommand {
+
+ private static final ObjectReader JSON_VALUE = new
ObjectMapper().readerFor(Object.class)
+ .with(DeserializationFeature.FAIL_ON_TRAILING_TOKENS);
+
+ @CommandLine.Option(names = "--evaluation", description = "Named semantic
definition to evaluate")
+ String evaluation;
+
+ @CommandLine.Option(names = "--body", description = "Sample message body
(text, file:path or json:value)")
+ String body;
+
+ @CommandLine.Option(names = "--header", description = "Sample header
(key=value; use json: for a typed value)")
+ List<String> headers;
+
+ @CommandLine.Option(names = "--variable",
+ description = "Sample exchange-local variable
(key=value; use json: for a typed value)")
+ List<String> variables;
+
+ @CommandLine.Option(names = "--expert", description = "Expert to call
directly")
+ String expert;
+
+ @CommandLine.Option(names = "--operation", description = "Expert operation
to call directly")
+ String operation;
+
+ @CommandLine.Option(names = "--input", description = "Direct expert input
(text, file:path or json:value)")
+ String input;
+
+ @CommandLine.Option(names = "--parameter", description = "Expert parameter
(key=value; use json: for a typed value)")
+ List<String> parameters;
+
+ @CommandLine.Option(names = "--evaluation-timeout", defaultValue = "50000",
+ description = "Provider evaluation timeout in
milliseconds (1-50000)")
+ long evaluationTimeout = 50000;
+
+ public SemanticEvaluate(CamelJBangMain main) {
+ super(main);
+ }
+
+ @Override
+ protected JsonObject request() {
+ if (evaluationTimeout < 1 || evaluationTimeout > 50000) {
+ throw new IllegalArgumentException("--evaluation-timeout must be
between 1 and 50000 milliseconds");
+ }
+ JsonObject request = new JsonObject();
+ request.put("action", "semantic-evaluate");
+ request.put("timeout", evaluationTimeout);
+ if (evaluation != null) {
+ requireText(evaluation, "--evaluation");
+ if (expert != null || operation != null || input != null ||
parameters != null) {
+ throw new IllegalArgumentException("Choose --evaluation or
--expert with --operation and --input");
+ }
+ request.put("evaluation", evaluation);
+ if (body != null) {
+ request.put("body", value(body, true));
+ }
+ if (headers != null) {
+ request.put("headers", values(headers, "--header"));
+ }
+ if (variables != null) {
+ JsonObject sampleVariables = values(variables, "--variable");
+ if (sampleVariables.keySet().stream().anyMatch(key ->
key.contains(":"))) {
+ throw new IllegalArgumentException(
+ "Sample variables must have exchange-local names
without a repository prefix");
+ }
+ request.put("variables", sampleVariables);
+ }
+ } else {
+ requireText(expert, "--expert");
Review Comment:
With neither `--evaluation` nor `--expert` given (for example `camel cmd
semantic-evaluate my-app`), the error is `--expert is required and must not be
blank`. That steers users toward the direct-call mode, although a named
evaluation is the more common case. Suggestion: when all of `evaluation`,
`expert`, `operation` and `input` are null, report `Choose --evaluation=<name>,
or --expert with --operation and --input` (still exit 2).
##########
dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/SemanticActionCommand.java:
##########
@@ -0,0 +1,151 @@
+/*
+ * 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.dsl.jbang.core.commands.action;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.util.Arrays;
+import java.util.List;
+import java.util.UUID;
+
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.dsl.jbang.core.common.CommandLineHelper;
+import org.apache.camel.util.json.JsonObject;
+import picocli.CommandLine;
+
+public abstract class SemanticActionCommand extends ActionBaseCommand {
+
+ @CommandLine.Parameters(description = "Name or pid of a running Camel
integration", arity = "0..1")
+ String name = "*";
+
+ @CommandLine.Option(names = "--json", description = "Output a single JSON
document")
+ boolean json;
+
+ @CommandLine.Option(names = "--timeout", defaultValue = "60000",
+ description = "Timeout in milliseconds waiting for the
integration")
+ long timeout = 60000;
+
+ @CommandLine.Spec
+ CommandLine.Model.CommandSpec commandSpec;
+
+ protected SemanticActionCommand(CamelJBangMain main) {
+ super(main);
+ }
+
+ @Override
+ public Integer doCall() {
+ try {
+ if (timeout <= 0) {
+ return error(2, "--timeout must be greater than zero", null);
+ }
+ JsonObject request;
+ try {
+ request = request();
+ } catch (IllegalArgumentException e) {
+ return error(2, e.getMessage(), null);
+ }
+ List<Long> pids =
findPids(name).stream().filter(this::isRunningIntegration).toList();
+ if (pids.isEmpty()) {
+ return error(3, "No running Camel integration matches: " +
name, null);
+ }
+ if (pids.size() != 1) {
+ return error(3, "Multiple Camel integrations match " + name +
": " + pids + ". Specify a pid.", null);
+ }
+ JsonObject response = execute(pids.get(0), request);
+ if (response == null) {
Review Comment:
If the selected application runs an older Camel version, its connector only
reads the legacy `{pid}-action.json`. It never picks up
`{pid}-action-{id}.json`, so the CLI waits the full `--timeout` (60 s by
default) and exits 4 with "No reply". The exit-code table says exit 3 for
"unavailable semantic tooling". This is likely to happen with `camel run
--camel-version=...` or an older Spring Boot or Quarkus app.
The status file already carries `context.version` (see
`CamelContextStatus`), so `isRunningIntegration` could also return exit 3
straight away when the version is older than the first release with per-request
action files and the semantic consoles (4.23). That gives a clear diagnostic
instead of a one-minute hang.
--
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]