This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch camel-3.20.x in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-3.20.x by this push: new e649884dc95 CAMEL-19001: camel-jbang - Backport 3.21 fixes and others to 3.20.x e649884dc95 is described below commit e649884dc9589819de6ac8c3dc651cd3923a6bc9 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Thu Feb 2 15:49:30 2023 +0100 CAMEL-19001: camel-jbang - Backport 3.21 fixes and others to 3.20.x --- .../apache/camel/dsl/jbang/core/commands/Bind.java | 18 +- .../dsl/jbang/core/commands/CamelJBangMain.java | 11 +- .../dsl/jbang/core/commands/CodeRestGenerator.java | 19 +- .../CamelTop.java => DependencyCommand.java} | 17 +- .../dsl/jbang/core/commands/DependencyCopy.java | 107 +++++ .../{DependencyTree.java => DependencyList.java} | 6 +- .../dsl/jbang/core/commands/ExportBaseCommand.java | 63 +-- .../dsl/jbang/core/commands/ExportQuarkus.java | 61 +++ .../apache/camel/dsl/jbang/core/commands/Init.java | 2 +- .../apache/camel/dsl/jbang/core/commands/Run.java | 250 ++++++++++-- .../core/commands/action/ActionBaseCommand.java | 4 - .../ActionWatchCommand.java} | 38 +- .../jbang/core/commands/action/CamelLogAction.java | 449 +++++++++++++++++++++ .../jbang/core/commands/action/CamelSourceTop.java | 5 +- .../core/commands/action/CamelThreadDump.java | 5 +- .../commands/action/RouteControllerAction.java | 5 +- .../core/commands/catalog/CatalogBaseCommand.java | 1 + .../jbang/core/commands/catalog/CatalogDoc.java | 2 +- .../core/commands/catalog/CatalogKamelet.java | 2 +- .../core/commands/process/CamelContextStatus.java | 4 +- .../core/commands/process/CamelContextTop.java | 4 +- .../jbang/core/commands/process/CamelCount.java | 4 +- .../commands/process/CamelProcessorStatus.java | 4 +- .../core/commands/process/CamelRouteStatus.java | 4 +- .../jbang/core/commands/process/CamelStatus.java | 9 +- .../dsl/jbang/core/commands/process/CamelTop.java | 9 +- .../dsl/jbang/core/commands/process/Hawtio.java | 4 +- .../jbang/core/commands/process/ListBlocked.java | 4 +- .../core/commands/process/ListCircuitBreaker.java | 4 +- ...{CamelEndpointStatus.java => ListEndpoint.java} | 6 +- .../dsl/jbang/core/commands/process/ListEvent.java | 4 +- .../jbang/core/commands/process/ListHealth.java | 4 +- .../jbang/core/commands/process/ListInflight.java | 4 +- .../jbang/core/commands/process/ListMetric.java | 4 +- .../jbang/core/commands/process/ListProcess.java | 5 +- .../jbang/core/commands/process/ListService.java | 4 +- .../dsl/jbang/core/commands/process/ListVault.java | 4 +- .../{CamelStatus.java => ProcessWatchCommand.java} | 40 +- .../camel/dsl/jbang/core/common/RuntimeUtil.java | 14 +- .../catalog => common}/VersionHelper.java | 4 +- .../camel/dsl/jbang/core/common/XmlHelper.java | 5 + ...ipe.properties => log4j2-background.properties} | 11 +- .../src/main/resources/log4j2-export.properties | 2 +- .../src/main/resources/log4j2-no-color.properties | 2 +- .../src/main/resources/log4j2-pipe.properties | 2 +- .../src/main/resources/log4j2.properties | 15 +- .../templates/run-custom-camel-version.tmpl} | 33 +- 47 files changed, 1094 insertions(+), 184 deletions(-) diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Bind.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Bind.java index 4f8d25739f5..6741b8019f9 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Bind.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Bind.java @@ -27,6 +27,7 @@ import java.util.Stack; import org.apache.camel.github.GitHubResourceResolver; import org.apache.camel.impl.engine.DefaultResourceResolvers; import org.apache.camel.spi.Resource; +import org.apache.camel.spi.ResourceResolver; import org.apache.camel.util.FileUtil; import org.apache.camel.util.IOHelper; import org.snakeyaml.engine.v2.api.LoadSettings; @@ -131,15 +132,26 @@ class Bind extends CamelCommand { InputStream is; String loc; + Resource res; // try local disk first before github - Resource res = new DefaultResourceResolvers.FileResolver().resolve("file:" + kamelet + ".kamelet.yaml"); + ResourceResolver resolver = new DefaultResourceResolvers.FileResolver(); + try { + res = resolver.resolve("file:" + kamelet + ".kamelet.yaml"); + } finally { + resolver.close(); + } if (res.exists()) { is = res.getInputStream(); loc = res.getLocation(); } else { - res = new GitHubResourceResolver().resolve( - "github:apache:camel-kamelets:main:kamelets/" + kamelet + ".kamelet.yaml"); + resolver = new GitHubResourceResolver(); + try { + res = resolver.resolve( + "github:apache:camel-kamelets:main:kamelets/" + kamelet + ".kamelet.yaml"); + } finally { + resolver.close(); + } loc = res.getLocation(); URL u = new URL(loc); is = u.openStream(); diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java index 49ed050991b..5176926abe2 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java @@ -22,6 +22,7 @@ import org.apache.camel.catalog.CamelCatalog; import org.apache.camel.catalog.DefaultCamelCatalog; import org.apache.camel.dsl.jbang.core.commands.action.CamelAction; import org.apache.camel.dsl.jbang.core.commands.action.CamelGCAction; +import org.apache.camel.dsl.jbang.core.commands.action.CamelLogAction; import org.apache.camel.dsl.jbang.core.commands.action.CamelReloadAction; import org.apache.camel.dsl.jbang.core.commands.action.CamelResetStatsAction; import org.apache.camel.dsl.jbang.core.commands.action.CamelRouteStartAction; @@ -41,7 +42,6 @@ import org.apache.camel.dsl.jbang.core.commands.catalog.CatalogOther; import org.apache.camel.dsl.jbang.core.commands.process.CamelContextStatus; import org.apache.camel.dsl.jbang.core.commands.process.CamelContextTop; import org.apache.camel.dsl.jbang.core.commands.process.CamelCount; -import org.apache.camel.dsl.jbang.core.commands.process.CamelEndpointStatus; import org.apache.camel.dsl.jbang.core.commands.process.CamelProcessorStatus; import org.apache.camel.dsl.jbang.core.commands.process.CamelProcessorTop; import org.apache.camel.dsl.jbang.core.commands.process.CamelRouteStatus; @@ -52,6 +52,7 @@ import org.apache.camel.dsl.jbang.core.commands.process.Hawtio; import org.apache.camel.dsl.jbang.core.commands.process.Jolokia; import org.apache.camel.dsl.jbang.core.commands.process.ListBlocked; import org.apache.camel.dsl.jbang.core.commands.process.ListCircuitBreaker; +import org.apache.camel.dsl.jbang.core.commands.process.ListEndpoint; import org.apache.camel.dsl.jbang.core.commands.process.ListEvent; import org.apache.camel.dsl.jbang.core.commands.process.ListHealth; import org.apache.camel.dsl.jbang.core.commands.process.ListInflight; @@ -72,6 +73,7 @@ public class CamelJBangMain implements Callable<Integer> { commandLine = new CommandLine(main) .addSubcommand("init", new CommandLine(new Init(main))) .addSubcommand("run", new CommandLine(new Run(main))) + .addSubcommand("log", new CommandLine(new CamelLogAction(main))) .addSubcommand("ps", new CommandLine(new ListProcess(main))) .addSubcommand("stop", new CommandLine(new StopProcess(main))) .addSubcommand("get", new CommandLine(new CamelStatus(main)) @@ -80,7 +82,7 @@ public class CamelJBangMain implements Callable<Integer> { .addSubcommand("processor", new CommandLine(new CamelProcessorStatus(main))) .addSubcommand("count", new CommandLine(new CamelCount(main))) .addSubcommand("health", new CommandLine(new ListHealth(main))) - .addSubcommand("endpoint", new CommandLine(new CamelEndpointStatus(main))) + .addSubcommand("endpoint", new CommandLine(new ListEndpoint(main))) .addSubcommand("event", new CommandLine(new ListEvent(main))) .addSubcommand("inflight", new CommandLine(new ListInflight(main))) .addSubcommand("blocked", new CommandLine(new ListBlocked(main))) @@ -103,6 +105,9 @@ public class CamelJBangMain implements Callable<Integer> { .addSubcommand("thread-dump", new CommandLine(new CamelThreadDump(main))) .addSubcommand("logger", new CommandLine(new LoggerAction(main))) .addSubcommand("gc", new CommandLine(new CamelGCAction(main)))) + .addSubcommand("dependency", new CommandLine(new DependencyCommand(main)) + .addSubcommand("list", new CommandLine(new DependencyList(main))) + .addSubcommand("copy", new CommandLine(new DependencyCopy(main)))) .addSubcommand("generate", new CommandLine(new CodeGenerator(main)) .addSubcommand("rest", new CommandLine(new CodeRestGenerator(main)))) .addSubcommand("catalog", new CommandLine(new CatalogCommand(main)) @@ -116,7 +121,7 @@ public class CamelJBangMain implements Callable<Integer> { .addSubcommand("hawtio", new CommandLine(new Hawtio(main))) .addSubcommand("bind", new CommandLine(new Bind(main))) .addSubcommand("pipe", new CommandLine(new Pipe(main))) - .addSubcommand("dependencies", new CommandLine(new DependencyTree(main))) + .addSubcommand("dependencies", new CommandLine(new DependencyList(main))) .addSubcommand("export", new CommandLine(new Export(main))) .addSubcommand("completion", new CommandLine(new Complete(main))); diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CodeRestGenerator.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CodeRestGenerator.java index 7db7d0785d7..41787ebfe36 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CodeRestGenerator.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CodeRestGenerator.java @@ -56,7 +56,8 @@ public class CodeRestGenerator extends CamelCommand { private boolean generateRoutes; @CommandLine.Option(names = { "-d", "--dto" }, description = "Data Objects") private boolean generateDataObjects; - @CommandLine.Option(names = { "-run", "--runtime" }, description = "Runtime (quarkus, spring-boot)", defaultValue = "quarkus") + @CommandLine.Option(names = { "-run", "--runtime" }, description = "Runtime (quarkus, spring-boot)", + defaultValue = "quarkus") private String runtime; @CommandLine.Option(names = { "-p", "--package" }, description = "Package for generated models", defaultValue = "model") private String packageName; @@ -104,14 +105,14 @@ public class CodeRestGenerator extends CamelCommand { } private void generateDto() throws IOException { - final String CODE = "code"; - final String GENERATOR_NAME = "quarkus".equals(runtime) ? "jaxrs-spec" : "java-camel"; - final String LIBRARY = "quarkus".equals(runtime) ? "quarkus" : "spring-boot"; + final String code = "code"; + final String generatorName = "quarkus".equals(runtime) ? "jaxrs-spec" : "java-camel"; + final String library = "quarkus".equals(runtime) ? "quarkus" : "spring-boot"; File output = Files.createTempDirectory("gendto").toFile(); final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName(GENERATOR_NAME) - .setLibrary(LIBRARY) + .setGeneratorName(generatorName) + .setLibrary(library) .setInputSpec(input) .setModelPackage(packageName) .setAdditionalProperties( @@ -122,14 +123,12 @@ public class CodeRestGenerator extends CamelCommand { GENERATE_MODELS, "true", "generatePom", "false", "generateApis", "false", - "sourceFolder", CODE - ) - ) + "sourceFolder", code)) .setOutputDir(output.getAbsolutePath()); final ClientOptInput clientOptInput = configurator.toClientOptInput(); new DefaultGenerator().opts(clientOptInput).generate(); - File generated = new File(Paths.get(output.getAbsolutePath(), CODE, packageName).toUri()); + File generated = new File(Paths.get(output.getAbsolutePath(), code, packageName).toUri()); generated.renameTo(new File(packageName)); } } diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTop.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyCommand.java similarity index 64% copy from dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTop.java copy to dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyCommand.java index 9f0b3b8c1a0..e34619741ec 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTop.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyCommand.java @@ -14,24 +14,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.dsl.jbang.core.commands.process; +package org.apache.camel.dsl.jbang.core.commands; -import org.apache.camel.dsl.jbang.core.commands.CamelCommand; -import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; import picocli.CommandLine; -@CommandLine.Command(name = "top", - description = "Top status of Camel integrations (use top --help to see sub commands)") -public class CamelTop extends CamelCommand { +@CommandLine.Command(name = "dependency", + description = "Displays all Camel dependencies required to run (use dependency --help to see sub commands)") +public class DependencyCommand extends CamelCommand { - public CamelTop(CamelJBangMain main) { + public DependencyCommand(CamelJBangMain main) { super(main); } @Override public Integer call() throws Exception { - // default to top the integrations - new CommandLine(new CamelContextTop(getMain())).execute(); + // default to list + new CommandLine(new DependencyList(getMain())).execute(); return 0; } + } diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyCopy.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyCopy.java new file mode 100644 index 00000000000..bd033fa954f --- /dev/null +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyCopy.java @@ -0,0 +1,107 @@ +/* + * 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; + +import java.io.File; +import java.util.Properties; +import java.util.concurrent.TimeUnit; + +import org.apache.camel.dsl.jbang.core.common.RuntimeUtil; +import org.apache.camel.util.CamelCaseOrderedProperties; +import org.apache.camel.util.FileUtil; +import picocli.CommandLine; + +@CommandLine.Command(name = "copy", + description = "Copies all Camel dependencies required to run to a specific directory") +public class DependencyCopy extends Export { + + protected static final String EXPORT_DIR = ".camel-jbang/export"; + + @CommandLine.Option(names = { "--output-directory" }, description = "Directory where dependencies should be copied", + defaultValue = "lib", required = true) + protected String outputDirectory; + + public DependencyCopy(CamelJBangMain main) { + super(main); + } + + @Override + protected Integer export() throws Exception { + this.quiet = true; // be quiet and generate from fresh data to ensure the output is up-to-date + + Integer answer = doExport(); + if (answer == 0) { + File buildDir = new File(EXPORT_DIR); + Process p = Runtime.getRuntime() + .exec("mvn dependency:copy-dependencies -DincludeScope=compile -DexcludeGroupIds=org.fusesource.jansi,org.apache.logging.log4j -DoutputDirectory=../../" + + outputDirectory, + null, + buildDir); + boolean done = p.waitFor(30, TimeUnit.SECONDS); + if (!done) { + answer = 1; + } + // cleanup dir after complete + FileUtil.removeDir(buildDir); + } + return answer; + } + + protected Integer doExport() throws Exception { + // read runtime and gav from profile if not configured + File profile = new File(getProfile() + ".properties"); + if (profile.exists()) { + Properties prop = new CamelCaseOrderedProperties(); + RuntimeUtil.loadProperties(prop, profile); + if (this.runtime == null) { + this.runtime = prop.getProperty("camel.jbang.runtime"); + } + if (this.gav == null) { + this.gav = prop.getProperty("camel.jbang.gav"); + } + // allow configuring versions from profile + this.javaVersion = prop.getProperty("camel.jbang.javaVersion", this.javaVersion); + this.kameletsVersion = prop.getProperty("camel.jbang.kameletsVersion", this.kameletsVersion); + this.localKameletDir = prop.getProperty("camel.jbang.localKameletDir", this.localKameletDir); + this.quarkusGroupId = prop.getProperty("camel.jbang.quarkusGroupId", this.quarkusGroupId); + this.quarkusArtifactId = prop.getProperty("camel.jbang.quarkusArtifactId", this.quarkusArtifactId); + this.quarkusVersion = prop.getProperty("camel.jbang.quarkusVersion", this.quarkusVersion); + this.springBootVersion = prop.getProperty("camel.jbang.springBootVersion", this.springBootVersion); + } + + // use temporary export dir + exportDir = EXPORT_DIR; + if (gav == null) { + gav = "org.apache.camel:camel-jbang-dummy:1.0"; + } + if (runtime == null) { + runtime = "camel-main"; + } + + if ("spring-boot".equals(runtime) || "camel-spring-boot".equals(runtime)) { + return export(new ExportSpringBoot(getMain())); + } else if ("quarkus".equals(runtime) || "camel-quarkus".equals(runtime)) { + return export(new ExportQuarkus(getMain())); + } else if ("main".equals(runtime) || "camel-main".equals(runtime)) { + return export(new ExportCamelMain(getMain())); + } else { + System.err.println("Unknown runtime: " + runtime); + return 1; + } + } + +} diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyTree.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyList.java similarity index 98% rename from dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyTree.java rename to dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyList.java index 040150d1123..3dc475b2cad 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyTree.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyList.java @@ -35,16 +35,16 @@ import org.apache.camel.util.CamelCaseOrderedProperties; import org.apache.camel.util.FileUtil; import picocli.CommandLine; -@CommandLine.Command(name = "dependencies", +@CommandLine.Command(name = "list", description = "Displays all Camel dependencies required to run") -public class DependencyTree extends Export { +public class DependencyList extends Export { protected static final String EXPORT_DIR = ".camel-jbang/export"; @CommandLine.Option(names = { "--output" }, description = "Output format (gav or maven)", defaultValue = "gav") protected String output; - public DependencyTree(CamelJBangMain main) { + public DependencyList(CamelJBangMain main) { super(main); } diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java index 54139ce6228..4016c4cc556 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java @@ -79,7 +79,7 @@ abstract class ExportBaseCommand extends CamelCommand { protected String javaVersion; @CommandLine.Option(names = { - "--kamelets-version" }, description = "Apache Camel Kamelets version", defaultValue = "3.20.0") + "--kamelets-version" }, description = "Apache Camel Kamelets version", defaultValue = "3.20.1.1") protected String kameletsVersion; @CommandLine.Option(names = { "--local-kamelet-dir" }, @@ -370,13 +370,16 @@ abstract class ExportBaseCommand extends CamelCommand { if (profile.exists()) { RuntimeUtil.loadProperties(prop2, profile); } + prop2.putAll(prop); + prepareApplicationProperties(prop2); for (Map.Entry<Object, Object> entry : prop.entrySet()) { String key = entry.getKey().toString(); - boolean skip = "camel.main.routesCompileDirectory".equals(key) + boolean skip = !key.startsWith("camel.main") + || "camel.main.routesCompileDirectory".equals(key) || "camel.main.routesReloadEnabled".equals(key); - if (!skip && key.startsWith("camel.main")) { - prop2.put(entry.getKey(), entry.getValue()); + if (skip) { + prop2.remove(key); } } @@ -385,33 +388,39 @@ abstract class ExportBaseCommand extends CamelCommand { } FileOutputStream fos = new FileOutputStream(new File(targetDir, "application.properties"), false); - for (Map.Entry<Object, Object> entry : prop2.entrySet()) { - String k = entry.getKey().toString(); - String v = entry.getValue().toString(); + try { + for (Map.Entry<Object, Object> entry : prop2.entrySet()) { + String k = entry.getKey().toString(); + String v = entry.getValue().toString(); - boolean skip = k.startsWith("camel.jbang.") || k.startsWith("jkube."); - if (skip) { - continue; - } + boolean skip = k.startsWith("camel.jbang.") || k.startsWith("jkube."); + if (skip) { + continue; + } - // files are now loaded in classpath - v = v.replaceAll("file:", "classpath:"); - if ("camel.main.routesIncludePattern".equals(k)) { - // camel.main.routesIncludePattern should remove all .java as we use spring boot - // to load them - // camel.main.routesIncludePattern should remove all file: classpath: as we copy - // them to src/main/resources/camel where camel auto-load from - v = Arrays.stream(v.split(",")) - .filter(n -> !n.endsWith(".java") && !n.startsWith("file:") && !n.startsWith("classpath:")) - .collect(Collectors.joining(",")); - } - if (!v.isBlank()) { - String line = applicationPropertyLine(k, v); - fos.write(line.getBytes(StandardCharsets.UTF_8)); - fos.write("\n".getBytes(StandardCharsets.UTF_8)); + // files are now loaded in classpath + v = v.replaceAll("file:", "classpath:"); + if ("camel.main.routesIncludePattern".equals(k)) { + // camel.main.routesIncludePattern should remove all .java as we use move them to regular src/main/java + // camel.main.routesIncludePattern should remove all file: classpath: as we copy + // them to src/main/resources/camel where camel autoload from + v = Arrays.stream(v.split(",")) + .filter(n -> !n.endsWith(".java") && !n.startsWith("file:") && !n.startsWith("classpath:")) + .collect(Collectors.joining(",")); + } + if (!v.isBlank()) { + String line = applicationPropertyLine(k, v); + fos.write(line.getBytes(StandardCharsets.UTF_8)); + fos.write("\n".getBytes(StandardCharsets.UTF_8)); + } } + } finally { + IOHelper.close(fos); } - IOHelper.close(fos); + } + + protected void prepareApplicationProperties(Properties properties) { + // noop } protected void copyMavenWrapper() throws Exception { diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java index cc44f627417..bdfcda47383 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java @@ -20,9 +20,13 @@ import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.Properties; import java.util.Set; +import java.util.StringJoiner; +import java.util.stream.Collectors; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -143,6 +147,63 @@ class ExportQuarkus extends Export { return 0; } + @Override + protected void prepareApplicationProperties(Properties properties) { + // quarkus native compilation only works if we specify each resource explicit + + StringJoiner sj = new StringJoiner(","); + StringJoiner sj2 = new StringJoiner(","); + for (Map.Entry<Object, Object> entry : properties.entrySet()) { + String k = entry.getKey().toString(); + String v = entry.getValue().toString(); + + if ("camel.main.routesIncludePattern".equals(k)) { + v = Arrays.stream(v.split(",")) + .map(ExportQuarkus::removeScheme) // remove scheme and routes are in camel sub-folder + .map(s -> "camel/" + s) + .collect(Collectors.joining(",")); + sj.add(v); + } + // extra classpath files + if ("camel.jbang.classpathFiles".equals(k)) { + v = Arrays.stream(v.split(",")) + .map(ExportQuarkus::removeScheme) // remove scheme + .collect(Collectors.joining(",")); + sj2.add(v); + } + } + + String routes = sj.length() > 0 ? sj.toString() : null; + String extra = sj2.length() > 0 ? sj2.toString() : null; + + if (routes != null || extra != null) { + sj = new StringJoiner(","); + String e = properties.getProperty("quarkus.native.resources.includes"); + if (e != null) { + sj.add(e); + } + if (routes != null) { + sj.add(routes); + } + if (extra != null) { + sj.add(extra); + } + if (sj.length() > 0) { + properties.setProperty("quarkus.native.resources.includes", sj.toString()); + } + if (routes != null) { + properties.setProperty("camel.main.routes-include-pattern", routes); + } + } + } + + private static String removeScheme(String s) { + if (s.contains(":")) { + return StringHelper.after(s, ":"); + } + return s; + } + private void createGradleProperties(File output) throws Exception { InputStream is = ExportQuarkus.class.getClassLoader().getResourceAsStream("templates/quarkus-gradle-properties.tmpl"); String context = IOHelper.loadText(is); diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Init.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Init.java index 85ee118ff2b..1d3ce0d93e4 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Init.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Init.java @@ -59,7 +59,7 @@ class Init extends CamelCommand { private String fromKamelet; @Option(names = { - "--kamelets-version" }, description = "Apache Camel Kamelets version", defaultValue = "3.20.0") + "--kamelets-version" }, description = "Apache Camel Kamelets version", defaultValue = "3.20.1.1") private String kameletsVersion; @Option(names = { diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java index dd59b5d4eb5..a543981cd9f 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java @@ -49,7 +49,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.apicurio.datamodels.Library; import io.apicurio.datamodels.openapi.models.OasDocument; import org.apache.camel.CamelContext; +import org.apache.camel.catalog.DefaultCamelCatalog; import org.apache.camel.dsl.jbang.core.common.RuntimeUtil; +import org.apache.camel.dsl.jbang.core.common.VersionHelper; import org.apache.camel.generator.openapi.RestDslGenerator; import org.apache.camel.impl.lw.LightweightCamelContext; import org.apache.camel.main.KameletMain; @@ -93,6 +95,8 @@ class Run extends CamelCommand { private boolean silentRun; private boolean pipeRun; + private File logFile; + //CHECKSTYLE:OFF @Parameters(description = "The Camel file(s) to run. If no files specified then application.properties is used as source for which files to run.", arity = "0..9", paramLabel = "<files>", parameterConsumer = FilesConsumer.class) @@ -100,6 +104,12 @@ class Run extends CamelCommand { List<String> files = new ArrayList<>(); + @Option(names = { "--background" }, defaultValue = "false", description = "Run in the background") + boolean background; + + @Option(names = { "--camel-version" }, description = "To run using a different Camel version than the default version.") + String camelVersion; + @Option(names = { "--profile" }, scope = CommandLine.ScopeType.INHERIT, defaultValue = "application", description = "Profile to use, which refers to loading properties file with the given profile name. By default application.properties is loaded.") String profile; @@ -264,32 +274,12 @@ class Run extends CamelCommand { removeDir(work); work.mkdirs(); - Properties profileProperties = null; - File profilePropertiesFile = new File(getProfile() + ".properties"); - if (profilePropertiesFile.exists()) { - profileProperties = loadProfileProperties(profilePropertiesFile); - // logging level/color may be configured in the properties file - loggingLevel = profileProperties.getProperty("loggingLevel", loggingLevel); - loggingColor - = "true".equals(profileProperties.getProperty("loggingColor", loggingColor ? "true" : "false")); - loggingJson - = "true".equals(profileProperties.getProperty("loggingJson", loggingJson ? "true" : "false")); - if (propertiesFiles == null) { - propertiesFiles = "file:" + profilePropertiesFile.getName(); - } else { - propertiesFiles = propertiesFiles + ",file:" + profilePropertiesFile.getName(); - } - repos = profileProperties.getProperty("camel.jbang.repos", repos); - mavenSettings = profileProperties.getProperty("camel.jbang.maven-settings", mavenSettings); - mavenSettingsSecurity = profileProperties.getProperty("camel.jbang.maven-settings-security", mavenSettingsSecurity); - openapi = profileProperties.getProperty("camel.jbang.openApi", openapi); - download = "true".equals(profileProperties.getProperty("camel.jbang.download", download ? "true" : "false")); - } - - // generate open-api early + Properties profileProperties = loadProfileProperties(); + configureLogging(); if (openapi != null) { generateOpenApi(); } + // route code as option if (code != null) { // store code in temporary file @@ -303,7 +293,9 @@ class Run extends CamelCommand { String routes = profileProperties != null ? profileProperties.getProperty("camel.main.routesIncludePattern") : null; if (routes == null) { if (!silentRun) { - System.out.println("Cannot run because " + getProfile() + ".properties file does not exist"); + System.out + .println("Cannot run because " + getProfile() + + ".properties file does not exist or camel.main.routesIncludePattern is not configured"); return 1; } else { // silent-run then auto-detect all files (except properties as they are loaded explicit or via profile) @@ -319,11 +311,7 @@ class Run extends CamelCommand { files = files.stream().distinct().collect(Collectors.toList()); } - // configure logging first - configureLogging(); - final KameletMain main = createMainInstance(); - main.setRepos(repos); main.setDownload(download); main.setFresh(fresh); @@ -344,11 +332,12 @@ class Run extends CamelCommand { if (modeline) { writeSetting(main, profileProperties, "camel.main.modeline", "true"); } - writeSetting(main, profileProperties, "camel.jbang.openApi", openapi); + writeSetting(main, profileProperties, "camel.jbang.open-api", openapi); writeSetting(main, profileProperties, "camel.jbang.repos", repos); writeSetting(main, profileProperties, "camel.jbang.health", health ? "true" : "false"); writeSetting(main, profileProperties, "camel.jbang.console", console ? "true" : "false"); - writeSetting(main, profileProperties, "camel.main.routesCompileDirectory", WORK_DIR); + // the runtime version of Camel is what is loaded via the catalog + writeSetting(main, profileProperties, "camel.jbang.camel-version", new DefaultCamelCatalog().getCatalogVersion()); // merge existing dependencies with --deps String deps = RuntimeUtil.getDependencies(profileProperties); if (deps.isBlank()) { @@ -391,7 +380,7 @@ class Run extends CamelCommand { () -> maxIdleSeconds > 0 ? String.valueOf(maxIdleSeconds) : null); writeSetting(main, profileProperties, "camel.jbang.platform-http.port", () -> port > 0 ? String.valueOf(port) : null); - writeSetting(main, profileProperties, "camel.jbang.jfr", jfr || jfrProfile != null ? "jfr" : null); + writeSetting(main, profileProperties, "camel.jbang.jfr", jfr || jfrProfile != null ? "jfr" : null); // TODO: "true" instead of "jfr" ? writeSetting(main, profileProperties, "camel.jbang.jfr-profile", jfrProfile != null ? jfrProfile : null); StringJoiner js = new StringJoiner(","); @@ -481,7 +470,6 @@ class Run extends CamelCommand { sjReload.add(file.substring(5)); } } - writeSetting(main, profileProperties, "camel.main.name", name); if (js.length() > 0) { @@ -557,9 +545,198 @@ class Run extends CamelCommand { writeSettings("camel.component.properties.location", loc); } + // okay we have validated all input and are ready to run + if (camelVersion != null) { + // run in another JVM with different camel version (foreground or background) + boolean custom = camelVersion.contains("-"); + if (custom) { + // custom camel distribution + return runCustomCamelVersion(main); + } else { + // apache camel distribution + return runCamelVersion(main); + } + } else if (background) { + // spawn new JVM to run in background + return runBackground(main); + } else { + // run default in current JVM with same camel version + return runKameletMain(main); + } + } + + private Properties loadProfileProperties() throws Exception { + Properties answer = null; + + File profilePropertiesFile = new File(getProfile() + ".properties"); + if (profilePropertiesFile.exists()) { + answer = loadProfileProperties(profilePropertiesFile); + // logging level/color may be configured in the properties file + loggingLevel = answer.getProperty("loggingLevel", loggingLevel); + loggingColor + = "true".equals(answer.getProperty("loggingColor", loggingColor ? "true" : "false")); + loggingJson + = "true".equals(answer.getProperty("loggingJson", loggingJson ? "true" : "false")); + if (propertiesFiles == null) { + propertiesFiles = "file:" + getProfile() + ".properties"; + } else { + propertiesFiles = propertiesFiles + ",file:" + profilePropertiesFile.getName(); + } + repos = answer.getProperty("camel.jbang.repos", repos); + mavenSettings = answer.getProperty("camel.jbang.maven-settings", mavenSettings); + mavenSettingsSecurity = answer.getProperty("camel.jbang.maven-settings-security", mavenSettingsSecurity); + openapi = answer.getProperty("camel.jbang.open-api", openapi); + download = "true".equals(answer.getProperty("camel.jbang.download", download ? "true" : "false")); + background = "true".equals(answer.getProperty("camel.jbang.background", background ? "true" : "false")); + camelVersion = answer.getProperty("camel.jbang.camel-version", camelVersion); + } + return answer; + } + + protected int runCamelVersion(KameletMain main) throws Exception { + String cmd = ProcessHandle.current().info().commandLine().orElse(null); + if (cmd != null) { + cmd = StringHelper.after(cmd, "main.CamelJBang "); + } + if (cmd == null) { + System.err.println("No Camel integration files to run"); + return 1; + } + if (background) { + cmd = cmd.replaceFirst("--background=true", ""); + cmd = cmd.replaceFirst("--background", ""); + } + cmd = cmd.replaceFirst("--camel-version=" + camelVersion, ""); + // need to use jbang command to specify camel version + String jbang = "jbang run -Dcamel.jbang.version=" + camelVersion; + if (repos != null) { + jbang += " --repos=" + repos; + } + cmd = jbang + " camel@apache/camel " + cmd; + + ProcessBuilder pb = new ProcessBuilder(); + String[] arr = cmd.split("\\s+"); // TODO: safe split + List<String> args = Arrays.asList(arr); + pb.command(args); + if (background) { + Process p = pb.start(); + System.out.println("Running Camel integration: " + name + " (version: " + camelVersion + + ") in background with PID: " + p.pid()); + return 0; + } else { + pb.inheritIO(); // run in foreground (with IO so logs are visible) + Process p = pb.start(); + // wait for that process to exit as we run in foreground + return p.waitFor(); + } + } + + protected int runBackground(KameletMain main) throws Exception { + String cmd = ProcessHandle.current().info().commandLine().orElse(null); + if (cmd != null) { + cmd = StringHelper.after(cmd, "main.CamelJBang "); + } + if (cmd == null) { + System.err.println("No Camel integration files to run"); + return 1; + } + cmd = cmd.replaceFirst("--background=true", ""); + cmd = cmd.replaceFirst("--background", ""); + cmd = "camel " + cmd; + + ProcessBuilder pb = new ProcessBuilder(); + String[] arr = cmd.split("\\s+"); // TODO: safe split + List<String> args = Arrays.asList(arr); + pb.command(args); + Process p = pb.start(); + System.out.println("Running Camel integration: " + name + " in background with PID: " + p.pid()); + return 0; + } + + protected int runCustomCamelVersion(KameletMain main) throws Exception { + InputStream is = Run.class.getClassLoader().getResourceAsStream("templates/run-custom-camel-version.tmpl"); + String content = IOHelper.loadText(is); + IOHelper.close(is); + + content = content.replaceFirst("\\{\\{ \\.JavaVersion }}", "11"); // TODO: java 11 or 17 + if (repos != null) { + content = content.replaceFirst("\\{\\{ \\.MavenRepositories }}", "//REPOS " + repos); + } + + // use custom distribution of camel + StringBuilder sb = new StringBuilder(); + sb.append(String.format("//DEPS org.apache.camel:camel-bom:%s@pom\n", camelVersion)); + sb.append(String.format("//DEPS org.apache.camel:camel-core:%s\n", camelVersion)); + sb.append(String.format("//DEPS org.apache.camel:camel-core-engine:%s\n", camelVersion)); + sb.append(String.format("//DEPS org.apache.camel:camel-main:%s\n", camelVersion)); + sb.append(String.format("//DEPS org.apache.camel:camel-java-joor-dsl:%s\n", camelVersion)); + sb.append(String.format("//DEPS org.apache.camel:camel-kamelet:%s\n", camelVersion)); + content = content.replaceFirst("\\{\\{ \\.CamelDependencies }}", sb.toString()); + + // use apache distribution of camel-jbang + String v = camelVersion.substring(0, camelVersion.lastIndexOf('.')); + sb = new StringBuilder(); + sb.append(String.format("//DEPS org.apache.camel:camel-jbang-core:%s\n", v)); + sb.append(String.format("//DEPS org.apache.camel:camel-kamelet-main:%s\n", v)); + sb.append(String.format("//DEPS org.apache.camel:camel-resourceresolver-github:%s\n", v)); + if (VersionHelper.isGE(v, "3.19.0")) { + sb.append(String.format("//DEPS org.apache.camel:camel-cli-connector:%s\n", v)); + } + content = content.replaceFirst("\\{\\{ \\.CamelJBangDependencies }}", sb.toString()); + + String fn = WORK_DIR + "/CustomCamelJBang.java"; + Files.write(Paths.get(fn), content.getBytes(StandardCharsets.UTF_8)); + + String cmd = ProcessHandle.current().info().commandLine().orElse(null); + if (cmd != null) { + cmd = StringHelper.after(cmd, "main.CamelJBang "); + } + if (cmd == null) { + System.err.println("No Camel integration files to run"); + return 1; + } + if (background) { + cmd = cmd.replaceFirst("--background=true", ""); + cmd = cmd.replaceFirst("--background", ""); + } + if (repos != null) { + if (!VersionHelper.isGE(v, "3.18.1")) { + // --repos is not supported in 3.18.0 or older, so remove + cmd = cmd.replaceFirst("--repos=" + repos, ""); + } + } + + cmd = cmd.replaceFirst("--camel-version=" + camelVersion, ""); + // need to use jbang command to specify camel version + String jbang = "jbang " + WORK_DIR + "/CustomCamelJBang.java "; + cmd = jbang + cmd; + + ProcessBuilder pb = new ProcessBuilder(); + String[] arr = cmd.split("\\s+"); // TODO: safe split + List<String> args = Arrays.asList(arr); + pb.command(args); + if (background) { + Process p = pb.start(); + System.out.println("Running Camel integration: " + name + " (version: " + camelVersion + + ") in background with PID: " + p.pid()); + return 0; + } else { + pb.inheritIO(); // run in foreground (with IO so logs are visible) + Process p = pb.start(); + // wait for that process to exit as we run in foreground + return p.waitFor(); + } + } + + protected int runKameletMain(KameletMain main) throws Exception { main.start(); main.run(); + // cleanup and delete log file + if (logFile != null) { + FileUtil.deleteFile(logFile); + } + return main.getExitCode(); } @@ -667,7 +844,7 @@ class Run extends CamelCommand { return file; } - private KameletMain createMainInstance() throws Exception { + private KameletMain createMainInstance() { KameletMain main; if (localKameletDir == null || localKameletDir.isEmpty()) { main = new KameletMain(); @@ -701,6 +878,13 @@ class Run extends CamelCommand { writeSettings("loggingLevel", loggingLevel); writeSettings("loggingColor", loggingColor ? "true" : "false"); writeSettings("loggingJson", loggingJson ? "true" : "false"); + if (!pipeRun) { + // remember log file + File dir = new File(System.getProperty("user.home"), ".camel"); + String name = RuntimeUtil.getPid() + ".log"; + logFile = new File(dir, name); + logFile.deleteOnExit(); + } } else { RuntimeUtil.configureLog("off", false, false, false, false); writeSettings("loggingLevel", "off"); diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/ActionBaseCommand.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/ActionBaseCommand.java index 4381965d9d6..ff2f019c13e 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/ActionBaseCommand.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/ActionBaseCommand.java @@ -20,7 +20,6 @@ import java.io.File; import java.io.FileInputStream; import java.util.ArrayList; import java.util.List; -import java.util.regex.Pattern; import org.apache.camel.dsl.jbang.core.commands.CamelCommand; import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; @@ -33,9 +32,6 @@ import org.apache.camel.util.json.Jsoner; abstract class ActionBaseCommand extends CamelCommand { - private static final String[] DSL_EXT = new String[] { "groovy", "java", "js", "jsh", "kts", "xml", "yaml" }; - private static final Pattern PATTERN = Pattern.compile("([\\w|\\-.])+"); - public ActionBaseCommand(CamelJBangMain main) { super(main); } diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelStatus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/ActionWatchCommand.java similarity index 51% copy from dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelStatus.java copy to dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/ActionWatchCommand.java index 3f3c44df414..8fbd5421db5 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelStatus.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/ActionWatchCommand.java @@ -14,24 +14,44 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.dsl.jbang.core.commands.process; +package org.apache.camel.dsl.jbang.core.commands.action; -import org.apache.camel.dsl.jbang.core.commands.CamelCommand; import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; +import org.fusesource.jansi.Ansi; +import org.fusesource.jansi.AnsiConsole; import picocli.CommandLine; -@CommandLine.Command(name = "get", - description = "Get status of Camel integrations (use get --help to see sub commands)") -public class CamelStatus extends CamelCommand { +abstract class ActionWatchCommand extends ActionBaseCommand { - public CamelStatus(CamelJBangMain main) { + @CommandLine.Option(names = { "--watch" }, + description = "Execute periodically and showing output fullscreen") + boolean watch; + + public ActionWatchCommand(CamelJBangMain main) { super(main); } @Override public Integer call() throws Exception { - // default to get the integrations - new CommandLine(new CamelContextStatus(getMain())).execute(); - return 0; + int exit; + if (watch) { + do { + exit = doCall(); + if (exit == 0) { + // use 2-sec delay in watch mode + Thread.sleep(2000); + } + } while (exit == 0); + } else { + exit = doCall(); + } + return exit; + } + + protected void clearScreen() { + AnsiConsole.out().print(Ansi.ansi().eraseScreen().cursor(1, 1)); } + + protected abstract Integer doCall() throws Exception; + } diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelLogAction.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelLogAction.java new file mode 100644 index 00000000000..75d934dadc6 --- /dev/null +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelLogAction.java @@ -0,0 +1,449 @@ +/* + * 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.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.LineNumberReader; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.regex.Pattern; + +import org.apache.camel.catalog.impl.TimePatternConverter; +import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; +import org.apache.camel.dsl.jbang.core.common.ProcessHelper; +import org.apache.camel.util.StopWatch; +import org.apache.camel.util.StringHelper; +import org.apache.camel.util.json.JsonObject; +import org.fusesource.jansi.Ansi; +import org.fusesource.jansi.AnsiConsole; +import picocli.CommandLine; + +@CommandLine.Command(name = "log", + description = "Tail logs from running Camel integrations") +public class CamelLogAction extends ActionBaseCommand { + + private static final int NAME_MAX_WIDTH = 25; + private static final int NAME_MIN_WIDTH = 10; + + @CommandLine.Parameters(description = "Name or pid of running Camel integration. (default selects all)", arity = "0..1") + String name = "*"; + + @CommandLine.Option(names = { "--logging-color" }, defaultValue = "true", description = "Use colored logging") + boolean loggingColor = true; + + @CommandLine.Option(names = { "--timestamp" }, defaultValue = "true", + description = "Print timestamp.") + boolean timestamp = true; + + @CommandLine.Option(names = { "--follow" }, defaultValue = "true", + description = "Keep following and outputting new log lines (use ctrl + c to exit).") + boolean follow = true; + + @CommandLine.Option(names = { "--prefix" }, defaultValue = "true", + description = "Print prefix with running Camel integration name.") + boolean prefix = true; + + @CommandLine.Option(names = { "--tail" }, + description = "The number of lines from the end of the logs to show. Defaults to showing all logs.") + int tail; + + @CommandLine.Option(names = { "--since" }, + description = "Return logs newer than a relative duration like 5s, 2m, or 1h. The value is in seconds if no unit specified.") + String since; + + @CommandLine.Option(names = { "--find" }, + description = "Find and highlight matching text (ignore case).", arity = "0..*") + String[] find; + + @CommandLine.Option(names = { "--grep" }, + description = "Filter logs to only output lines matching text (ignore case).", arity = "0..*") + String[] grep; + + String findAnsi; + + private int nameMaxWidth; + + private final Map<String, Ansi.Color> colors = new HashMap<>(); + + public CamelLogAction(CamelJBangMain main) { + super(main); + } + + @Override + public Integer call() throws Exception { + Map<Long, Row> rows = new LinkedHashMap<>(); + + // find new pids + updatePids(rows); + if (!rows.isEmpty()) { + // read existing log files (skip by tail/since) + if (find != null) { + findAnsi = Ansi.ansi().fg(Ansi.Color.BLACK).bg(Ansi.Color.YELLOW).a("$0").reset().toString(); + for (int i = 0; i < find.length; i++) { + String f = find[i]; + f = Pattern.quote(f); + find[i] = f; + } + } + if (grep != null) { + findAnsi = Ansi.ansi().fg(Ansi.Color.BLACK).bg(Ansi.Color.YELLOW).a("$0").reset().toString(); + for (int i = 0; i < grep.length; i++) { + String f = grep[i]; + f = Pattern.quote(f); + grep[i] = f; + } + } + Date limit = null; + if (since != null) { + long millis; + if (StringHelper.isDigit(since)) { + // is in seconds by default + millis = TimePatternConverter.toMilliSeconds(since) * 1000; + } else { + millis = TimePatternConverter.toMilliSeconds(since); + } + limit = new Date(System.currentTimeMillis() - millis); + } + + // dump existing log lines + tailLogFiles(rows, tail, limit); + dumpLogFiles(rows, tail); + } + + if (follow) { + boolean waitMessage = true; + StopWatch watch = new StopWatch(); + do { + if (rows.isEmpty()) { + if (waitMessage) { + System.out.println("Waiting for logs ..."); + waitMessage = false; + } + Thread.sleep(500); + updatePids(rows); + } else { + waitMessage = true; + if (watch.taken() > 500) { + // check for new logs + updatePids(rows); + watch.restart(); + } + int lines = readLogFiles(rows); + if (lines > 0) { + dumpLogFiles(rows, 0); + } else { + Thread.sleep(100); + } + } + } while (true); + } + + return 0; + } + + private void updatePids(Map<Long, Row> rows) { + List<Long> pids = findPids(name); + ProcessHandle.allProcesses() + .filter(ph -> pids.contains(ph.pid())) + .forEach(ph -> { + JsonObject root = loadStatus(ph.pid()); + if (root != null) { + Row row = new Row(); + row.pid = "" + ph.pid(); + JsonObject context = (JsonObject) root.get("context"); + if (context == null) { + return; + } + row.name = context.getString("name"); + if ("CamelJBang".equals(row.name)) { + row.name = ProcessHelper.extractName(root, ph); + } + int len = row.name.length(); + if (len < NAME_MIN_WIDTH) { + len = NAME_MIN_WIDTH; + } + if (len > NAME_MAX_WIDTH) { + len = NAME_MAX_WIDTH; + } + if (len > nameMaxWidth) { + nameMaxWidth = len; + } + if (!rows.containsKey(ph.pid())) { + rows.put(ph.pid(), row); + } + } + }); + + // remove pids that are no long active from the rows + Set<Long> remove = new HashSet<>(); + for (long pid : rows.keySet()) { + if (!pids.contains(pid)) { + remove.add(pid); + } + } + for (long pid : remove) { + rows.remove(pid); + } + } + + private int readLogFiles(Map<Long, Row> rows) throws Exception { + int lines = 0; + + for (Row row : rows.values()) { + if (row.reader == null) { + File log = logFile(row.pid); + if (log.exists()) { + row.reader = new LineNumberReader(new FileReader(log)); + } + } + if (row.reader != null) { + String line; + do { + try { + line = row.reader.readLine(); + if (line != null) { + boolean valid = true; + if (grep != null) { + valid = isValidGrep(line); + } + if (valid) { + lines++; + // switch fifo to be unlimited as we use it for new log lines + if (row.fifo == null || row.fifo instanceof ArrayBlockingQueue) { + row.fifo = new ArrayDeque<>(); + } + row.fifo.offer(line); + } + } + } catch (IOException e) { + // ignore + line = null; + } + } while (line != null); + } + } + + return lines; + } + + private void dumpLogFiles(Map<Long, Row> rows, int tail) { + List<String> lines = new ArrayList<>(); + for (Row row : rows.values()) { + Queue<String> queue = row.fifo; + if (queue != null) { + for (String l : queue) { + lines.add(row.name + "| " + l); + } + row.fifo.clear(); + } + } + // sort lines + lines.sort(this::compareLogLine); + if (tail > 0) { + // cut according to tail + int pos = lines.size() - tail; + if (pos > 0) { + lines = lines.subList(pos, lines.size()); + } + } + lines.forEach(l -> { + String name = StringHelper.before(l, "| "); + String line = StringHelper.after(l, "| "); + printLine(name, line); + }); + } + + private int compareLogLine(String l1, String l2) { + l1 = unescapeAnsi(l1); + l2 = unescapeAnsi(l2); + + String t1 = StringHelper.after(l1, "| "); + t1 = StringHelper.before(t1, " "); + String t2 = StringHelper.after(l2, "| "); + t2 = StringHelper.before(t2, " "); + return t1.compareTo(t2); + } + + protected void printLine(String name, String line) { + if (!prefix) { + name = null; + } + if (!timestamp) { + // after timestamp is after 2 sine-space + int pos = line.indexOf(' '); + pos = line.indexOf(' ', pos + 1); + if (pos != -1) { + line = line.substring(pos + 1); + } + } + if (loggingColor) { + if (name != null) { + Ansi.Color color = colors.get(name); + if (color == null) { + // grab a new color + int idx = (colors.size() % 6) + 1; + color = Ansi.Color.values()[idx]; + colors.put(name, color); + } + String n = String.format("%-" + nameMaxWidth + "s", name); + AnsiConsole.out().print(Ansi.ansi().fg(color).a(n).a("| ").reset()); + } + } else { + line = unescapeAnsi(line); + if (name != null) { + String n = String.format("%-" + nameMaxWidth + "s", name); + System.out.print(n); + System.out.print("| "); + } + } + if (find != null || grep != null) { + String before = StringHelper.before(line, "---"); + String after = StringHelper.after(line, "---"); + if (find != null) { + for (String f : find) { + after = after.replaceAll("(?i)" + f, findAnsi); + } + } + if (grep != null) { + for (String g : grep) { + after = after.replaceAll("(?i)" + g, findAnsi); + } + } + line = before + "---" + after; + } + if (loggingColor) { + AnsiConsole.out().println(line); + } else { + System.out.println(line); + } + } + + private static File logFile(String pid) { + File dir = new File(System.getProperty("user.home"), ".camel"); + String name = pid + ".log"; + return new File(dir, name); + } + + private void tailLogFiles(Map<Long, Row> rows, int tail, Date limit) throws Exception { + for (Row row : rows.values()) { + File log = logFile(row.pid); + if (log.exists()) { + row.reader = new LineNumberReader(new FileReader(log)); + String line; + if (tail == 0) { + row.fifo = new ArrayDeque<>(); + } else { + row.fifo = new ArrayBlockingQueue<>(tail); + } + do { + line = row.reader.readLine(); + if (line != null) { + boolean valid = isValidSince(limit, line); + if (valid && grep != null) { + valid = isValidGrep(line); + } + if (valid) { + while (!row.fifo.offer(line)) { + row.fifo.poll(); + } + } + } + } while (line != null); + } + } + } + + private boolean isValidSince(Date limit, String line) { + if (limit == null) { + return true; + } + // the log can be in color or not so we need to unescape always + line = unescapeAnsi(line); + String ts = StringHelper.before(line, " "); + + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + try { + Date row = sdf.parse(ts); + return row.compareTo(limit) >= 0; + } catch (ParseException e) { + // ignore + } + return false; + } + + private boolean isValidGrep(String line) { + if (grep == null) { + return true; + } + // the log can be in color or not so we need to unescape always + line = unescapeAnsi(line); + String after = StringHelper.after(line, "---"); + for (String g : grep) { + boolean m = Pattern.compile("(?i)" + g).matcher(after).find(); + if (m) { + return true; + } + } + return false; + } + + private String unescapeAnsi(String line) { + // unescape ANSI colors + StringBuilder sb = new StringBuilder(); + boolean escaping = false; + char[] arr = line.toCharArray(); + for (int i = 0; i < arr.length; i++) { + char ch = arr[i]; + if (escaping) { + if (ch == 'm') { + escaping = false; + } + continue; + } + char ch2 = i < arr.length - 1 ? arr[i + 1] : 0; + if (ch == 27 && ch2 == '[') { + escaping = true; + continue; + } + + sb.append(ch); + } + return sb.toString(); + } + + private static class Row { + String pid; + String name; + Queue<String> fifo; + LineNumberReader reader; + + } + +} diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSourceTop.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSourceTop.java index 5c6a4215591..bda0bb38c11 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSourceTop.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSourceTop.java @@ -33,7 +33,7 @@ import picocli.CommandLine; import picocli.CommandLine.Command; @Command(name = "source", description = "List top processors (source) in a running Camel integration") -public class CamelSourceTop extends ActionBaseCommand { +public class CamelSourceTop extends ActionWatchCommand { @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "1") String name; @@ -53,7 +53,7 @@ public class CamelSourceTop extends ActionBaseCommand { } @Override - public Integer call() throws Exception { + public Integer doCall() throws Exception { List<Row> rows = new ArrayList<>(); List<Long> pids = findPids(name); @@ -140,6 +140,7 @@ public class CamelSourceTop extends ActionBaseCommand { // sort rows rows.sort(this::sortRow); + clearScreen(); if (!rows.isEmpty()) { printSource(rows); } diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelThreadDump.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelThreadDump.java index e12dbd2dda0..1ee5b4c147f 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelThreadDump.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelThreadDump.java @@ -38,7 +38,7 @@ import picocli.CommandLine; import picocli.CommandLine.Command; @Command(name = "thread-dump", description = "List threads in a running Camel integration") -public class CamelThreadDump extends ActionBaseCommand { +public class CamelThreadDump extends ActionWatchCommand { @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "1") String name; @@ -66,7 +66,7 @@ public class CamelThreadDump extends ActionBaseCommand { } @Override - public Integer call() throws Exception { + public Integer doCall() throws Exception { List<Row> rows = new ArrayList<>(); List<Long> pids = findPids(name); @@ -132,6 +132,7 @@ public class CamelThreadDump extends ActionBaseCommand { // sort rows rows.sort(this::sortRow); + clearScreen(); if (!rows.isEmpty()) { int total = jo.getInteger("threadCount"); int peak = jo.getInteger("peakThreadCount"); diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/RouteControllerAction.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/RouteControllerAction.java index 5412738ce7e..f5e0a85acfd 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/RouteControllerAction.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/RouteControllerAction.java @@ -39,7 +39,7 @@ import picocli.CommandLine; import picocli.CommandLine.Command; @Command(name = "route-controller", description = "List status of route controller in a running Camel integration") -public class RouteControllerAction extends ActionBaseCommand { +public class RouteControllerAction extends ActionWatchCommand { @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "1") String name; @@ -67,7 +67,7 @@ public class RouteControllerAction extends ActionBaseCommand { } @Override - public Integer call() throws Exception { + public Integer doCall() throws Exception { List<Row> rows = new ArrayList<>(); List<Long> pids = findPids(name); @@ -134,6 +134,7 @@ public class RouteControllerAction extends ActionBaseCommand { // sort rows rows.sort(this::sortRow); + clearScreen(); if (!rows.isEmpty()) { if (supervising) { if (header) { diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogBaseCommand.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogBaseCommand.java index 448bba7a364..5cb43bfe1ae 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogBaseCommand.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogBaseCommand.java @@ -28,6 +28,7 @@ import org.apache.camel.catalog.CamelCatalog; import org.apache.camel.catalog.DefaultCamelCatalog; import org.apache.camel.dsl.jbang.core.commands.CamelCommand; import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; +import org.apache.camel.dsl.jbang.core.common.VersionHelper; import org.apache.camel.main.download.MavenGav; import org.apache.camel.tooling.model.ArtifactModel; import picocli.CommandLine; diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDoc.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDoc.java index c5866b117fb..33297b470f2 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDoc.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDoc.java @@ -70,7 +70,7 @@ public class CatalogDoc extends CamelCommand { boolean headers; @CommandLine.Option(names = { - "--kamelets-version" }, description = "Apache Camel Kamelets version", defaultValue = "3.20.0") + "--kamelets-version" }, description = "Apache Camel Kamelets version", defaultValue = "3.20.1.1") String kameletsVersion; final CamelCatalog catalog = new DefaultCamelCatalog(true); diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogKamelet.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogKamelet.java index 0d9903a6ef0..bf8af192b3c 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogKamelet.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogKamelet.java @@ -52,7 +52,7 @@ public class CatalogKamelet extends CamelCommand { String filterName; @CommandLine.Option(names = { - "--kamelets-version" }, description = "Apache Camel Kamelets version", defaultValue = "3.20.0") + "--kamelets-version" }, description = "Apache Camel Kamelets version", defaultValue = "3.20.1.1") String kameletsVersion; public CatalogKamelet(CamelJBangMain main) { diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextStatus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextStatus.java index 1a331516dba..eb87dc1f2fb 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextStatus.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextStatus.java @@ -35,7 +35,7 @@ import picocli.CommandLine.Command; @Command(name = "context", description = "Get status of Camel integrations") -public class CamelContextStatus extends ProcessBaseCommand { +public class CamelContextStatus extends ProcessWatchCommand { @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1") String name = "*"; @@ -49,7 +49,7 @@ public class CamelContextStatus extends ProcessBaseCommand { } @Override - public Integer call() throws Exception { + public Integer doCall() throws Exception { List<Row> rows = new ArrayList<>(); List<Long> pids = findPids(name); diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextTop.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextTop.java index 9cdbcc8c334..ed36eb58b8e 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextTop.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextTop.java @@ -34,7 +34,7 @@ import picocli.CommandLine.Command; @Command(name = "context", description = "Top status of Camel integrations") -public class CamelContextTop extends ProcessBaseCommand { +public class CamelContextTop extends ProcessWatchCommand { @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1") String name = "*"; @@ -48,7 +48,7 @@ public class CamelContextTop extends ProcessBaseCommand { } @Override - public Integer call() throws Exception { + public Integer doCall() throws Exception { List<Row> rows = new ArrayList<>(); List<Long> pids = findPids(name); diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelCount.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelCount.java index 69515307887..f43d3f6819c 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelCount.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelCount.java @@ -34,7 +34,7 @@ import picocli.CommandLine.Command; @Command(name = "count", description = "Get total and failed exchanges for running integrations") -public class CamelCount extends ProcessBaseCommand { +public class CamelCount extends ProcessWatchCommand { @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1") String name = "*"; @@ -56,7 +56,7 @@ public class CamelCount extends ProcessBaseCommand { } @Override - public Integer call() throws Exception { + public Integer doCall() throws Exception { List<Row> rows = new ArrayList<>(); List<Long> pids = findPids(name); diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelProcessorStatus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelProcessorStatus.java index 39a30060c69..f752d71da1d 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelProcessorStatus.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelProcessorStatus.java @@ -35,7 +35,7 @@ import picocli.CommandLine; import picocli.CommandLine.Command; @Command(name = "processor", description = "Get status of Camel processors") -public class CamelProcessorStatus extends ProcessBaseCommand { +public class CamelProcessorStatus extends ProcessWatchCommand { @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1") String name = "*"; @@ -61,7 +61,7 @@ public class CamelProcessorStatus extends ProcessBaseCommand { } @Override - public Integer call() throws Exception { + public Integer doCall() throws Exception { List<Row> rows = new ArrayList<>(); List<Long> pids = findPids(name); diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelRouteStatus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelRouteStatus.java index f5cb0545a34..2e65d9ec7a3 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelRouteStatus.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelRouteStatus.java @@ -34,7 +34,7 @@ import picocli.CommandLine; import picocli.CommandLine.Command; @Command(name = "route", description = "Get status of Camel routes") -public class CamelRouteStatus extends ProcessBaseCommand { +public class CamelRouteStatus extends ProcessWatchCommand { @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1") String name = "*"; @@ -64,7 +64,7 @@ public class CamelRouteStatus extends ProcessBaseCommand { } @Override - public Integer call() throws Exception { + public Integer doCall() throws Exception { List<Row> rows = new ArrayList<>(); List<Long> pids = findPids(name); diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelStatus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelStatus.java index 3f3c44df414..596cd72c7b8 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelStatus.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelStatus.java @@ -24,6 +24,10 @@ import picocli.CommandLine; description = "Get status of Camel integrations (use get --help to see sub commands)") public class CamelStatus extends CamelCommand { + @CommandLine.Option(names = { "--watch" }, + description = "Execute periodically and showing output fullscreen") + boolean watch; + public CamelStatus(CamelJBangMain main) { super(main); } @@ -31,7 +35,8 @@ public class CamelStatus extends CamelCommand { @Override public Integer call() throws Exception { // default to get the integrations - new CommandLine(new CamelContextStatus(getMain())).execute(); - return 0; + CamelContextStatus cmd = new CamelContextStatus(getMain()); + cmd.watch = watch; + return new CommandLine(cmd).execute(); } } diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTop.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTop.java index 9f0b3b8c1a0..5a3af05e8f3 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTop.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTop.java @@ -24,6 +24,10 @@ import picocli.CommandLine; description = "Top status of Camel integrations (use top --help to see sub commands)") public class CamelTop extends CamelCommand { + @CommandLine.Option(names = { "--watch" }, + description = "Execute periodically and showing output fullscreen") + boolean watch; + public CamelTop(CamelJBangMain main) { super(main); } @@ -31,7 +35,8 @@ public class CamelTop extends CamelCommand { @Override public Integer call() throws Exception { // default to top the integrations - new CommandLine(new CamelContextTop(getMain())).execute(); - return 0; + CamelContextTop cmd = new CamelContextTop(getMain()); + cmd.watch = watch; + return new CommandLine(cmd).execute(); } } diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/Hawtio.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/Hawtio.java index b5d925231fa..8d9e1dcd1ff 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/Hawtio.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/Hawtio.java @@ -37,8 +37,8 @@ public class Hawtio extends CamelCommand { String name; @CommandLine.Option(names = { "--version" }, - description = "Version of the Hawtio web console", defaultValue = "2.16.2") - String version = "2.16.2"; + description = "Version of the Hawtio web console", defaultValue = "2.17.0") + String version = "2.17.0"; // use port 8888 as 8080 is too commonly used @CommandLine.Option(names = { "--port" }, diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListBlocked.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListBlocked.java index 5cc8ac73359..800eba36ca3 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListBlocked.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListBlocked.java @@ -34,7 +34,7 @@ import picocli.CommandLine.Command; @Command(name = "blocked", description = "Get blocked messages of Camel integrations") -public class ListBlocked extends ProcessBaseCommand { +public class ListBlocked extends ProcessWatchCommand { @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1") String name = "*"; @@ -48,7 +48,7 @@ public class ListBlocked extends ProcessBaseCommand { } @Override - public Integer call() throws Exception { + public Integer doCall() throws Exception { List<Row> rows = new ArrayList<>(); List<Long> pids = findPids(name); diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListCircuitBreaker.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListCircuitBreaker.java index d91051babaa..9d79ed9568e 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListCircuitBreaker.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListCircuitBreaker.java @@ -34,7 +34,7 @@ import picocli.CommandLine.Command; @Command(name = "circuit-breaker", description = "Get status of Circuit Breaker EIPs") -public class ListCircuitBreaker extends ProcessBaseCommand { +public class ListCircuitBreaker extends ProcessWatchCommand { @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1") String name = "*"; @@ -48,7 +48,7 @@ public class ListCircuitBreaker extends ProcessBaseCommand { } @Override - public Integer call() throws Exception { + public Integer doCall() throws Exception { List<Row> rows = new ArrayList<>(); List<Long> pids = findPids(name); diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelEndpointStatus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListEndpoint.java similarity index 98% rename from dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelEndpointStatus.java rename to dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListEndpoint.java index 53d2c44192f..e3205346c86 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelEndpointStatus.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListEndpoint.java @@ -34,7 +34,7 @@ import picocli.CommandLine; import picocli.CommandLine.Command; @Command(name = "endpoint", description = "Get usage of Camel endpoints") -public class CamelEndpointStatus extends ProcessBaseCommand { +public class ListEndpoint extends ProcessWatchCommand { @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1") String name = "*"; @@ -63,12 +63,12 @@ public class CamelEndpointStatus extends ProcessBaseCommand { description = "List endpoint URI without query parameters (short)") boolean shortUri; - public CamelEndpointStatus(CamelJBangMain main) { + public ListEndpoint(CamelJBangMain main) { super(main); } @Override - public Integer call() throws Exception { + public Integer doCall() throws Exception { List<Row> rows = new ArrayList<>(); // make it easier to filter diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListEvent.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListEvent.java index 9f201aecc24..fca78be3c4a 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListEvent.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListEvent.java @@ -34,7 +34,7 @@ import picocli.CommandLine.Command; @Command(name = "event", description = "Get latest events of Camel integrations") -public class ListEvent extends ProcessBaseCommand { +public class ListEvent extends ProcessWatchCommand { @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1") String name = "*"; @@ -52,7 +52,7 @@ public class ListEvent extends ProcessBaseCommand { } @Override - public Integer call() throws Exception { + public Integer doCall() throws Exception { List<Row> rows = new ArrayList<>(); List<Long> pids = findPids(name); diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListHealth.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListHealth.java index 5ba23909a2a..8d69917ba7b 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListHealth.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListHealth.java @@ -40,7 +40,7 @@ import picocli.CommandLine; import picocli.CommandLine.Command; @Command(name = "health", description = "Get health check status of running Camel integrations") -public class ListHealth extends ProcessBaseCommand { +public class ListHealth extends ProcessWatchCommand { @CommandLine.Option(names = { "--sort" }, description = "Sort by pid, name or age", defaultValue = "pid") @@ -75,7 +75,7 @@ public class ListHealth extends ProcessBaseCommand { } @Override - public Integer call() throws Exception { + public Integer doCall() throws Exception { final List<Row> rows = new ArrayList<>(); // include stack-traces diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListInflight.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListInflight.java index ce0ae54e0c5..941431dce9e 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListInflight.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListInflight.java @@ -34,7 +34,7 @@ import picocli.CommandLine.Command; @Command(name = "inflight", description = "Get inflight messages of Camel integrations") -public class ListInflight extends ProcessBaseCommand { +public class ListInflight extends ProcessWatchCommand { @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1") String name = "*"; @@ -48,7 +48,7 @@ public class ListInflight extends ProcessBaseCommand { } @Override - public Integer call() throws Exception { + public Integer doCall() throws Exception { List<Row> rows = new ArrayList<>(); List<Long> pids = findPids(name); diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListMetric.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListMetric.java index b4252053865..b69b646b1d9 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListMetric.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListMetric.java @@ -34,7 +34,7 @@ import picocli.CommandLine.Command; @Command(name = "metric", description = "Get metrics (micrometer) of running Camel integrations") -public class ListMetric extends ProcessBaseCommand { +public class ListMetric extends ProcessWatchCommand { @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1") String name = "*"; @@ -60,7 +60,7 @@ public class ListMetric extends ProcessBaseCommand { } @Override - public Integer call() throws Exception { + public Integer doCall() throws Exception { List<Row> rows = new ArrayList<>(); List<Long> pids = findPids(name); diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListProcess.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListProcess.java index 85a9475e3e8..8d67cfff03b 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListProcess.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListProcess.java @@ -32,7 +32,7 @@ import picocli.CommandLine; import picocli.CommandLine.Command; @Command(name = "ps", description = "List running Camel integrations") -public class ListProcess extends ProcessBaseCommand { +public class ListProcess extends ProcessWatchCommand { @CommandLine.Option(names = { "--sort" }, description = "Sort by pid, name or age", defaultValue = "pid") @@ -46,8 +46,7 @@ public class ListProcess extends ProcessBaseCommand { super(main); } - @Override - public Integer call() throws Exception { + protected Integer doCall() throws Exception { List<Row> rows = new ArrayList<>(); List<Long> pids = findPids("*"); diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListService.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListService.java index 3a45113de8b..9b56a84ef15 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListService.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListService.java @@ -34,7 +34,7 @@ import picocli.CommandLine.Command; @Command(name = "service", description = "Get services of Camel integrations") -public class ListService extends ProcessBaseCommand { +public class ListService extends ProcessWatchCommand { @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1") String name = "*"; @@ -48,7 +48,7 @@ public class ListService extends ProcessBaseCommand { } @Override - public Integer call() throws Exception { + public Integer doCall() throws Exception { List<Row> rows = new ArrayList<>(); List<Long> pids = findPids(name); diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListVault.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListVault.java index d6092254a00..8ce83a353cb 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListVault.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListVault.java @@ -34,7 +34,7 @@ import picocli.CommandLine.Command; @Command(name = "vault", description = "List secrets from security vaults used by running Camel integrations") -public class ListVault extends ProcessBaseCommand { +public class ListVault extends ProcessWatchCommand { @CommandLine.Option(names = { "--sort" }, description = "Sort by pid, name", defaultValue = "pid") @@ -45,7 +45,7 @@ public class ListVault extends ProcessBaseCommand { } @Override - public Integer call() throws Exception { + public Integer doCall() throws Exception { List<Row> rows = new ArrayList<>(); List<Long> pids = findPids("*"); diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelStatus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ProcessWatchCommand.java similarity index 52% copy from dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelStatus.java copy to dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ProcessWatchCommand.java index 3f3c44df414..cb8c6dbb560 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelStatus.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ProcessWatchCommand.java @@ -16,22 +16,46 @@ */ package org.apache.camel.dsl.jbang.core.commands.process; -import org.apache.camel.dsl.jbang.core.commands.CamelCommand; import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; +import org.fusesource.jansi.Ansi; +import org.fusesource.jansi.AnsiConsole; import picocli.CommandLine; -@CommandLine.Command(name = "get", - description = "Get status of Camel integrations (use get --help to see sub commands)") -public class CamelStatus extends CamelCommand { +/** + * Base class for commands that can run in watch mode. + */ +abstract class ProcessWatchCommand extends ProcessBaseCommand { + + @CommandLine.Option(names = { "--watch" }, + description = "Execute periodically and showing output fullscreen") + boolean watch; - public CamelStatus(CamelJBangMain main) { + public ProcessWatchCommand(CamelJBangMain main) { super(main); } @Override public Integer call() throws Exception { - // default to get the integrations - new CommandLine(new CamelContextStatus(getMain())).execute(); - return 0; + int exit; + if (watch) { + do { + clearScreen(); + exit = doCall(); + if (exit == 0) { + // use 2-sec delay in watch mode + Thread.sleep(2000); + } + } while (exit == 0); + } else { + exit = doCall(); + } + return exit; + } + + protected void clearScreen() { + AnsiConsole.out().print(Ansi.ansi().eraseScreen().cursor(1, 1)); } + + protected abstract Integer doCall() throws Exception; + } diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/RuntimeUtil.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/RuntimeUtil.java index edd832c98f8..837e698ef7e 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/RuntimeUtil.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/RuntimeUtil.java @@ -32,8 +32,12 @@ public final class RuntimeUtil { private RuntimeUtil() { } - public static void configureLog(String level, boolean color, boolean json, boolean pipe, boolean export) { + public static void configureLog( + String level, boolean color, boolean json, boolean pipe, boolean export) { if (INIT_DONE.compareAndSet(false, true)) { + long pid = ProcessHandle.current().pid(); + System.setProperty("pid", "" + pid); + if (export) { Configurator.initialize("CamelJBang", "log4j2-export.properties"); } else if (pipe) { @@ -99,4 +103,12 @@ public final class RuntimeUtil { return deps; } + public static String getPid() { + try { + return "" + ProcessHandle.current().pid(); + } catch (Throwable e) { + return null; + } + } + } diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/VersionHelper.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/VersionHelper.java similarity index 95% rename from dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/VersionHelper.java rename to dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/VersionHelper.java index 587a56b70d8..cc22c2985e5 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/VersionHelper.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/VersionHelper.java @@ -14,11 +14,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.dsl.jbang.core.commands.catalog; +package org.apache.camel.dsl.jbang.core.common; import org.apache.camel.util.StringHelper; -final class VersionHelper { +public final class VersionHelper { private VersionHelper() { } diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/XmlHelper.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/XmlHelper.java index afc58f99cd9..452307af4cd 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/XmlHelper.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/XmlHelper.java @@ -42,6 +42,11 @@ public final class XmlHelper { factory.setFeature("http://xml.org/sax/features/external-general-entities", false); } catch (ParserConfigurationException e) { } + try { + // Disable the external-parameter-entities by default + factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + } catch (ParserConfigurationException e) { + } // setup the SecurityManager by default if it's apache xerces try { Class<?> smClass = ObjectHelper.loadClass("org.apache.xerces.util.SecurityManager"); diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-pipe.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-background.properties similarity index 76% copy from dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-pipe.properties copy to dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-background.properties index f6ed178ad0d..5e700f81157 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-pipe.properties +++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-background.properties @@ -15,16 +15,17 @@ ## limitations under the License. ## --------------------------------------------------------------------------- +# file logger appender.file.type = File appender.file.name = file -appender.file.fileName = ${sys:user.home}/.camel/camel-pipe.log +appender.file.fileName = ${sys:user.home}/.camel/${sys:pid}.log appender.file.createOnDemand = true appender.file.append = false - appender.file.layout.type = PatternLayout -# logging style that is similar to spring boot (no color) -appender.file.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} %5p %pid --- [%15.15t] %-40.40c : %m%n +# logging style that is similar to spring boot +appender.file.layout.pattern = %style{%d{yyyy-MM-dd HH:mm:ss.SSS}}{Dim} %highlight{%5p} %style{%pid}{Magenta} %style{---}{Dim} %style{[%15.15t]}{Dim} %style{%-35.35c}{Cyan} : %m%n +# log to file +rootLogger = INFO,file rootLogger.level = INFO -rootLogger.appenderRef.out.ref = file diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-export.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-export.properties index c09e2c668a4..730ef1eb162 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-export.properties +++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-export.properties @@ -23,7 +23,7 @@ appender.file.append = false appender.file.layout.type = PatternLayout # logging style that is similar to spring boot (no color) -appender.file.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} %5p %pid --- [%15.15t] %-40.40c : %m%n +appender.file.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} %5p %pid --- [%15.15t] %-35.35c : %m%n rootLogger.level = INFO rootLogger.appenderRef.out.ref = file diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-no-color.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-no-color.properties index 2bb0c0ddc93..6dcdec667d3 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-no-color.properties +++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-no-color.properties @@ -20,7 +20,7 @@ appender.stdout.name = out appender.stdout.layout.type = PatternLayout # logging style that is similar to spring boot (no color) -appender.stdout.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} %5p %pid --- [%15.15t] %-40.40c : %m%n +appender.stdout.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} %5p %pid --- [%15.15t] %-35.35c : %m%n rootLogger.level = INFO rootLogger.appenderRef.out.ref = out diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-pipe.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-pipe.properties index f6ed178ad0d..1349f98ad8d 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-pipe.properties +++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-pipe.properties @@ -23,7 +23,7 @@ appender.file.append = false appender.file.layout.type = PatternLayout # logging style that is similar to spring boot (no color) -appender.file.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} %5p %pid --- [%15.15t] %-40.40c : %m%n +appender.file.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} %5p %pid --- [%15.15t] %-35.35c : %m%n rootLogger.level = INFO rootLogger.appenderRef.out.ref = file diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2.properties index bd77ce59db0..5561cfee4a4 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2.properties +++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2.properties @@ -15,13 +15,24 @@ ## limitations under the License. ## --------------------------------------------------------------------------- +# console logger appender.stdout.type = Console appender.stdout.name = out appender.stdout.layout.type = PatternLayout +# logging style that is similar to spring boot +appender.stdout.layout.pattern = %style{%d{yyyy-MM-dd HH:mm:ss.SSS}}{Dim} %highlight{%5p} %style{%pid}{Magenta} %style{---}{Dim} %style{[%15.15t]}{Dim} %style{%-35.35c}{Cyan} : %m%n +# file logger +appender.file.type = File +appender.file.name = file +appender.file.fileName = ${sys:user.home}/.camel/${sys:pid}.log +appender.file.createOnDemand = true +appender.file.append = false +appender.file.layout.type = PatternLayout # logging style that is similar to spring boot -appender.stdout.layout.pattern = %style{%d{yyyy-MM-dd HH:mm:ss.SSS}}{Dim} %highlight{%5p} %style{%pid}{Magenta} %style{---}{Dim} %style{[%15.15t]}{Dim} %style{%-40.40c}{Cyan} : %m%n +appender.file.layout.pattern = %style{%d{yyyy-MM-dd HH:mm:ss.SSS}}{Dim} %highlight{%5p} %style{%pid}{Magenta} %style{---}{Dim} %style{[%15.15t]}{Dim} %style{%-35.35c}{Cyan} : %m%n +# log to console and file +rootLogger = INFO,out,file rootLogger.level = INFO -rootLogger.appenderRef.out.ref = out diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTop.java b/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/run-custom-camel-version.tmpl similarity index 56% copy from dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTop.java copy to dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/run-custom-camel-version.tmpl index 9f0b3b8c1a0..cd15762a79f 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTop.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/run-custom-camel-version.tmpl @@ -1,3 +1,5 @@ +///usr/bin/env jbang "$0" "$@" ; exit $? + /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -6,7 +8,7 @@ * (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 + * 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, @@ -14,24 +16,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.dsl.jbang.core.commands.process; -import org.apache.camel.dsl.jbang.core.commands.CamelCommand; +//JAVA {{ .JavaVersion }}+ +{{ .MavenRepositories }} +//REPOS mavencentral,apache-snapshot=http://repository.apache.org/content/groups/snapshots/ +{{ .CamelDependencies }} +{{ .CamelJBangDependencies }} +//DEPS org.apache.camel.kamelets:camel-kamelets:${camel-kamelets.version:3.20.1.1} + +package main; + import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; -import picocli.CommandLine; -@CommandLine.Command(name = "top", - description = "Top status of Camel integrations (use top --help to see sub commands)") -public class CamelTop extends CamelCommand { +/** + * Main to run CamelJBang + */ +public class CustomCamelJBang { - public CamelTop(CamelJBangMain main) { - super(main); + public static void main(String... args) { + CamelJBangMain.run(args); } - @Override - public Integer call() throws Exception { - // default to top the integrations - new CommandLine(new CamelContextTop(getMain())).execute(); - return 0; - } }