davsclaus commented on code in PR #26753:
URL: https://github.com/apache/camel/pull/26753#discussion_r4075586215
##########
dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/ExpressionEvaluator.java:
##########
@@ -140,12 +182,87 @@ private static void evaluateLocally(
result.put("result", value != null ? value.toString() : null);
} catch (Exception e) {
result.put("status", "error");
- Throwable cause = e;
- while (cause.getCause() != null && cause.getCause() != cause) {
- cause = cause.getCause();
+ result.put("error", rootCause(e));
+ }
+ return true;
+ }
+
+ /**
+ * The catalog's own check of the text, which names where the syntax
breaks (its index), so an error says more than
+ * the evaluation's exception; only added when it finds something the
evaluation did not.
+ */
+ private static void syntaxCheck(
+ ToolContext ctx, ClassLoader loader, String lang, String
expression, boolean predicate, JsonObject result) {
+ if ("ok".equals(result.getString("status"))) {
+ return;
+ }
+ try {
+ LanguageValidationResult check = predicate
+ ? ctx.catalog().validateLanguagePredicate(loader, lang,
expression)
+ : ctx.catalog().validateLanguageExpression(loader, lang,
expression);
+ if (!check.isSuccess()) {
+ String error = check.getShortError() != null ?
check.getShortError() : check.getError();
+ if (error != null) {
+ result.put("syntaxError", error);
+ if (check.getIndex() >= 0) {
+ result.put("syntaxErrorAt", check.getIndex());
+ }
+ }
+ }
+ } catch (Exception e) {
+ // the catalog cannot check this language here; the evaluation's
own error stands
+ }
+ }
+
+ private static String rootCause(Throwable e) {
+ Throwable cause = e;
+ while (cause.getCause() != null && cause.getCause() != cause) {
+ cause = cause.getCause();
+ }
+ return cause.getMessage() != null ? cause.getMessage() :
cause.toString();
+ }
+
+ /** The groupId:artifactId:version of a language, from the catalog, or
null when the catalog does not know it. */
+ private static String languageArtifact(ToolContext ctx, String lang) {
+ try {
+ LanguageModel model = ctx.catalog().languageModel(lang);
+ if (model != null && model.getArtifactId() != null) {
+ return model.getGroupId() + ":" + model.getArtifactId() + ":"
+ model.getVersion();
+ }
+ } catch (Exception e) {
+ // the catalog does not know it
+ }
+ return null;
+ }
+
+ /**
+ * Downloads the component of a language and keeps its class loader, so
the next call does not download again.
+ * Returns null when there is nothing to download (an unknown name) or the
download fails (no network).
+ */
+ private static ClassLoader download(String gav) {
+ if (gav == null) {
+ return null;
+ }
+ ClassLoader cached = DOWNLOADED.get(gav);
+ if (cached != null) {
+ return cached;
+ }
+ String[] parts = gav.split(":");
+ try {
+ DependencyDownloaderClassLoader cl
+ = new
DependencyDownloaderClassLoader(ExpressionEvaluator.class.getClassLoader());
+ try (MavenDependencyDownloader downloader = new
MavenDependencyDownloader()) {
+ downloader.setClassLoader(cl);
+ downloader.start();
+ downloader.downloadDependency(parts[0], parts[1], parts[2]);
}
- String message = cause.getMessage();
- result.put("error", message != null ? message : cause.toString());
+ DOWNLOADED.put(gav, cl);
Review Comment:
Fixed: the download runs inside `DOWNLOADED.computeIfAbsent(gav, ...)`, so
two parallel evaluations of the same language download it once and no class
loader is left unreferenced. A failed download returns null from the mapping
function, which stores nothing, so the next call still retries.
##########
dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/ExpressionEvaluator.java:
##########
@@ -140,12 +182,87 @@ private static void evaluateLocally(
result.put("result", value != null ? value.toString() : null);
} catch (Exception e) {
result.put("status", "error");
- Throwable cause = e;
- while (cause.getCause() != null && cause.getCause() != cause) {
- cause = cause.getCause();
+ result.put("error", rootCause(e));
+ }
+ return true;
+ }
+
+ /**
+ * The catalog's own check of the text, which names where the syntax
breaks (its index), so an error says more than
+ * the evaluation's exception; only added when it finds something the
evaluation did not.
+ */
+ private static void syntaxCheck(
+ ToolContext ctx, ClassLoader loader, String lang, String
expression, boolean predicate, JsonObject result) {
+ if ("ok".equals(result.getString("status"))) {
+ return;
+ }
+ try {
+ LanguageValidationResult check = predicate
+ ? ctx.catalog().validateLanguagePredicate(loader, lang,
expression)
+ : ctx.catalog().validateLanguageExpression(loader, lang,
expression);
+ if (!check.isSuccess()) {
+ String error = check.getShortError() != null ?
check.getShortError() : check.getError();
+ if (error != null) {
+ result.put("syntaxError", error);
+ if (check.getIndex() >= 0) {
+ result.put("syntaxErrorAt", check.getIndex());
+ }
+ }
+ }
+ } catch (Exception e) {
+ // the catalog cannot check this language here; the evaluation's
own error stands
+ }
+ }
+
+ private static String rootCause(Throwable e) {
+ Throwable cause = e;
+ while (cause.getCause() != null && cause.getCause() != cause) {
+ cause = cause.getCause();
+ }
+ return cause.getMessage() != null ? cause.getMessage() :
cause.toString();
+ }
+
+ /** The groupId:artifactId:version of a language, from the catalog, or
null when the catalog does not know it. */
+ private static String languageArtifact(ToolContext ctx, String lang) {
+ try {
+ LanguageModel model = ctx.catalog().languageModel(lang);
+ if (model != null && model.getArtifactId() != null) {
+ return model.getGroupId() + ":" + model.getArtifactId() + ":"
+ model.getVersion();
+ }
+ } catch (Exception e) {
+ // the catalog does not know it
+ }
+ return null;
+ }
+
+ /**
+ * Downloads the component of a language and keeps its class loader, so
the next call does not download again.
+ * Returns null when there is nothing to download (an unknown name) or the
download fails (no network).
+ */
+ private static ClassLoader download(String gav) {
+ if (gav == null) {
+ return null;
+ }
+ ClassLoader cached = DOWNLOADED.get(gav);
+ if (cached != null) {
+ return cached;
+ }
+ String[] parts = gav.split(":");
+ try {
+ DependencyDownloaderClassLoader cl
+ = new
DependencyDownloaderClassLoader(ExpressionEvaluator.class.getClassLoader());
+ try (MavenDependencyDownloader downloader = new
MavenDependencyDownloader()) {
+ downloader.setClassLoader(cl);
+ downloader.start();
+ downloader.downloadDependency(parts[0], parts[1], parts[2]);
}
- String message = cause.getMessage();
- result.put("error", message != null ? message : cause.toString());
+ DOWNLOADED.put(gav, cl);
+ return cl;
+ } catch (Exception e) {
+ return null;
Review Comment:
Fixed: `download` now takes a `StringBuilder failure`, appends the exception
message (or its class name when there is none), and the answer appends it in
parentheses - so the model reads "... jq could not be downloaded (Cannot access
central in offline mode ...)" instead of a bare "could not be downloaded".
--
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]