This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push: new 4855c5e2476 CAMEL-18515: camel-jbang - Command to list kamelets from the catalog. 4855c5e2476 is described below commit 4855c5e2476d5ea4bd0d70e4e98b5539c9653378 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Fri Sep 16 23:47:22 2022 +0200 CAMEL-18515: camel-jbang - Command to list kamelets from the catalog. --- .../dsl/jbang/core/commands/CamelJBangMain.java | 4 + .../core/commands/kamelet/CatalogCommand.java | 35 ++++ .../core/commands/kamelet/CatalogKamelet.java | 206 +++++++++++++++++++++ 3 files changed, 245 insertions(+) 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 14b56996dd5..05fa2aa7921 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 @@ -28,6 +28,8 @@ import org.apache.camel.dsl.jbang.core.commands.action.CamelRouteStartAction; import org.apache.camel.dsl.jbang.core.commands.action.CamelRouteStopAction; import org.apache.camel.dsl.jbang.core.commands.action.CamelSourceTop; import org.apache.camel.dsl.jbang.core.commands.action.CamelThreadDump; +import org.apache.camel.dsl.jbang.core.commands.kamelet.CatalogCommand; +import org.apache.camel.dsl.jbang.core.commands.kamelet.CatalogKamelet; 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.CamelProcessorStatus; @@ -74,6 +76,8 @@ public class CamelJBangMain implements Callable<Integer> { .addSubcommand("gc", new CommandLine(new CamelGCAction(main)))) .addSubcommand("generate", new CommandLine(new CodeGenerator(main)) .addSubcommand("rest", new CommandLine(new CodeRestGenerator(main)))) + .addSubcommand("catalog", new CommandLine(new CatalogCommand(main)) + .addSubcommand("kamelet", new CommandLine(new CatalogKamelet(main)))) .addSubcommand("jolokia", new CommandLine(new Jolokia(main))) .addSubcommand("hawtio", new CommandLine(new Hawtio(main))) .addSubcommand("bind", new CommandLine(new Bind(main))) diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/kamelet/CatalogCommand.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/kamelet/CatalogCommand.java new file mode 100644 index 00000000000..da9d41dfe32 --- /dev/null +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/kamelet/CatalogCommand.java @@ -0,0 +1,35 @@ +/* + * 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.kamelet; + +import org.apache.camel.dsl.jbang.core.commands.CamelCommand; +import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; +import picocli.CommandLine; + +@CommandLine.Command(name = "catalog", description = "List artifacts from Camel Catalog (use --help to see sub commands)") +public class CatalogCommand extends CamelCommand { + + public CatalogCommand(CamelJBangMain main) { + super(main); + } + + @Override + public Integer call() throws Exception { + new CommandLine(this).execute("--help"); + return 0; + } +} diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/kamelet/CatalogKamelet.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/kamelet/CatalogKamelet.java new file mode 100644 index 00000000000..9598fa74741 --- /dev/null +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/kamelet/CatalogKamelet.java @@ -0,0 +1,206 @@ +/* + * 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.kamelet; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.stream.Collectors; + +import com.github.freva.asciitable.AsciiTable; +import com.github.freva.asciitable.Column; +import com.github.freva.asciitable.HorizontalAlign; +import org.apache.camel.dsl.jbang.core.commands.CamelCommand; +import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; +import org.apache.camel.main.download.DependencyDownloaderClassLoader; +import org.apache.camel.main.download.MavenDependencyDownloader; +import org.apache.camel.support.ObjectHelper; +import org.apache.camel.util.StringHelper; +import picocli.CommandLine; + +@CommandLine.Command(name = "kamelet", aliases = { "kamelet", "kamelets" }, + description = "List Kamelets from the Kamelet Catalog") +public class CatalogKamelet extends CamelCommand { + + @CommandLine.Option(names = { "--sort" }, + description = "Sort by name, type, level, or description", defaultValue = "name") + String sort; + + @CommandLine.Option(names = { "--type", "--filter-type" }, + description = "Filter by type: source, sink, or action") + String filterType; + + @CommandLine.Option(names = { "--filter" }, + description = "Filter by name or description") + String filterName; + + @CommandLine.Option(names = { + "--kamelets-version" }, description = "Apache Camel Kamelets version", defaultValue = "0.9.0") + String kameletsVersion; + + public CatalogKamelet(CamelJBangMain main) { + super(main); + } + + @Override + public Integer call() throws Exception { + List<Row> rows = new ArrayList<>(); + + Map<String, Object> kamelets; + try { + ClassLoader cl = createClassLoader(); + MavenDependencyDownloader downloader = new MavenDependencyDownloader(); + downloader.setClassLoader(cl); + downloader.start(); + downloader.downloadDependency("org.apache.camel.kamelets", "camel-kamelets-catalog", kameletsVersion); + + Thread.currentThread().setContextClassLoader(cl); + Class<?> clazz = cl.loadClass("org.apache.camel.kamelets.catalog.KameletsCatalog"); + Object catalog = clazz.getDeclaredConstructor().newInstance(); + Method m = clazz.getMethod("getKamelets"); + kamelets = (Map<String, Object>) ObjectHelper.invokeMethod(m, catalog); + } catch (Exception e) { + System.err.println("Cannot download camel-kamelets-catalog due to " + e.getMessage()); + return 1; + } + + for (Object o : kamelets.values()) { + Row row = new Row(); + row.name = getName(o); + row.type = getType(o); + row.level = getLevel(o); + row.description = getDescription(o); + rows.add(row); + } + + if (filterType != null) { + rows = rows.stream().filter(r -> r.type.equalsIgnoreCase(filterType)).collect(Collectors.toList()); + } + if (filterName != null) { + filterName = filterName.toLowerCase(Locale.ROOT); + rows = rows.stream().filter( + r -> r.name.equalsIgnoreCase(filterName) || r.description.toLowerCase(Locale.ROOT).contains(filterName)) + .collect(Collectors.toList()); + } + + // sort rows + rows.sort(this::sortRow); + + if (!rows.isEmpty()) { + System.out.println(AsciiTable.getTable(AsciiTable.NO_BORDERS, rows, Arrays.asList( + new Column().header("NAME").dataAlign(HorizontalAlign.LEFT).with(r -> r.name), + new Column().header("TYPE").dataAlign(HorizontalAlign.LEFT).with(r -> r.type), + new Column().header("LEVEL").dataAlign(HorizontalAlign.LEFT).with(r -> r.level), + new Column().header("DESCRIPTION").dataAlign(HorizontalAlign.LEFT).with(this::getDescription)))); + } + + return 0; + } + + protected int sortRow(Row o1, Row o2) { + String s = sort; + int negate = 1; + if (s.startsWith("-")) { + s = s.substring(1); + negate = -1; + } + switch (s) { + case "name": + return o1.name.compareToIgnoreCase(o2.name) * negate; + case "type": + return o1.type.compareToIgnoreCase(o2.type) * negate; + case "level": + return o1.level.compareToIgnoreCase(o2.level) * negate; + case "description": + return o1.description.compareToIgnoreCase(o2.description) * negate; + default: + return 0; + } + } + + private ClassLoader createClassLoader() { + ClassLoader parentCL = CatalogKamelet.class.getClassLoader(); + return new DependencyDownloaderClassLoader(parentCL); + } + + private String getName(Object kamelet) throws Exception { + Method m = kamelet.getClass().getMethod("getMetadata"); + Object meta = ObjectHelper.invokeMethod(m, kamelet); + m = meta.getClass().getMethod("getName"); + return (String) ObjectHelper.invokeMethod(m, meta); + } + + private String getType(Object kamelet) throws Exception { + Method m = kamelet.getClass().getMethod("getMetadata"); + Object meta = ObjectHelper.invokeMethod(m, kamelet); + m = meta.getClass().getMethod("getLabels"); + Map labels = (Map) ObjectHelper.invokeMethod(m, meta); + if (labels != null) { + return (String) labels.get("camel.apache.org/kamelet.type"); + } + return null; + } + + private String getLevel(Object kamelet) throws Exception { + Method m = kamelet.getClass().getMethod("getMetadata"); + Object meta = ObjectHelper.invokeMethod(m, kamelet); + m = meta.getClass().getMethod("getAnnotations"); + Map anns = (Map) ObjectHelper.invokeMethod(m, meta); + if (anns != null) { + return (String) anns.get("camel.apache.org/kamelet.support.level"); + } + return null; + } + + private String getDescription(Object kamelet) throws Exception { + Method m = kamelet.getClass().getMethod("getSpec"); + Object spec = ObjectHelper.invokeMethod(m, kamelet); + m = spec.getClass().getMethod("getDefinition"); + Object def = ObjectHelper.invokeMethod(m, spec); + m = def.getClass().getMethod("getDescription"); + return (String) ObjectHelper.invokeMethod(m, def); + } + + private static class Row { + private String name; + private String type; + private String level; + private String description; + } + + private String getDescription(Row r) { + String d = r.description; + if (d != null && d.contains(".")) { + // grab first sentence + d = StringHelper.before(d, "."); + d = d.trim(); + } + if (d != null && d.contains("\n")) { + // grab first sentence + d = StringHelper.before(d, "\n"); + d = d.trim(); + } + if (d == null) { + d = ""; + } + return d; + } + +}