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

commit e50d3cedfc2dfb93daadc04199718b49e24b15b8
Author: Claus Ibsen <[email protected]>
AuthorDate: Sun Sep 25 13:42:07 2022 +0200

    camel-jbang - get source command
---
 .../camel/cli/connector/LocalCliConnector.java     |  13 +-
 .../dsl/jbang/core/commands/CamelJBangMain.java    |   2 +
 .../core/commands/action/CamelSourceAction.java    | 236 +++++++++++++++++++++
 3 files changed, 247 insertions(+), 4 deletions(-)

diff --git 
a/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java
 
b/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java
index 35bd4b801b9..64cb2e9f0eb 100644
--- 
a/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java
+++ 
b/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java
@@ -271,6 +271,15 @@ public class LocalCliConnector extends ServiceSupport 
implements CliConnector, C
                     LOG.trace("Updating output file: {}", outputFile);
                     IOHelper.writeText(json.toJson(), outputFile);
                 }
+            } else if ("source".equals(action)) {
+                DevConsole dc = camelContext.adapt(ExtendedCamelContext.class)
+                        .getDevConsoleResolver().resolveDevConsole("source");
+                if (dc != null) {
+                    String filter = root.getString("filter");
+                    JsonObject json = (JsonObject) 
dc.call(DevConsole.MediaType.JSON, Map.of("filter", filter));
+                    LOG.trace("Updating output file: {}", outputFile);
+                    IOHelper.writeText(json.toJson(), outputFile);
+                }
             }
 
             // action done so delete file
@@ -285,10 +294,6 @@ public class LocalCliConnector extends ServiceSupport 
implements CliConnector, C
         }
     }
 
-    private void changeLoggingLevel(String level) {
-
-    }
-
     JsonObject loadAction() {
         try {
             if (actionFile != null && actionFile.exists()) {
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 f6667184096..3bd66b67e3c 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
@@ -26,6 +26,7 @@ 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;
 import org.apache.camel.dsl.jbang.core.commands.action.CamelRouteStopAction;
+import org.apache.camel.dsl.jbang.core.commands.action.CamelSourceAction;
 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.action.LoggerAction;
@@ -71,6 +72,7 @@ public class CamelJBangMain implements Callable<Integer> {
                         .addSubcommand("processor", new CommandLine(new 
CamelProcessorStatus(main)))
                         .addSubcommand("endpoint", new CommandLine(new 
CamelEndpointStatus(main)))
                         .addSubcommand("service", new CommandLine(new 
ListService(main)))
+                        .addSubcommand("source", new CommandLine(new 
CamelSourceAction(main)))
                         .addSubcommand("vault", new CommandLine(new 
ListVault(main))))
                 .addSubcommand("top", new CommandLine(new CamelTop(main))
                         .addSubcommand("context", new CommandLine(new 
CamelContextTop(main)))
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSourceAction.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSourceAction.java
new file mode 100644
index 00000000000..795fb3cb454
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSourceAction.java
@@ -0,0 +1,236 @@
+/*
+ * 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.FileInputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.support.PatternHelper;
+import org.apache.camel.util.FileUtil;
+import org.apache.camel.util.IOHelper;
+import org.apache.camel.util.StopWatch;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
+import org.apache.camel.util.json.Jsoner;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+
+import static 
org.apache.camel.support.LoggerHelper.stripSourceLocationLineNumber;
+
+@Command(name = "source", description = "Display Camel route source code")
+public class CamelSourceAction extends ActionBaseCommand {
+
+    // TODO: strip license header
+
+    @CommandLine.Parameters(description = "Name or pid of running Camel 
integration", arity = "1")
+    String name;
+
+    @CommandLine.Option(names = { "--filter" },
+                        description = "Filter source by filename (multiple 
names can be separated by comma)")
+    String filter;
+
+    @CommandLine.Option(names = { "--sort" },
+                        description = "Sort source by name", defaultValue = 
"name")
+    String sort;
+
+    private volatile long pid;
+
+    public CamelSourceAction(CamelJBangMain main) {
+        super(main);
+    }
+
+    @Override
+    public Integer call() throws Exception {
+        List<Row> rows = new ArrayList<>();
+
+        List<Long> pids = findPids(name);
+        if (pids.isEmpty()) {
+            return 0;
+        } else if (pids.size() > 1) {
+            System.out.println("Name or pid " + name + " matches " + 
pids.size()
+                               + " running Camel integrations. Specify a name 
or PID that matches exactly one.");
+            return 0;
+        }
+
+        this.pid = pids.get(0);
+
+        // ensure output file is deleted before executing action
+        File outputFile = getOutputFile("" + pid);
+        FileUtil.deleteFile(outputFile);
+
+        JsonObject root = new JsonObject();
+        root.put("action", "source");
+        root.put("filter", "*");
+        File file = getActionFile("" + pid);
+        try {
+            IOHelper.writeText(root.toJson(), file);
+        } catch (Exception e) {
+            // ignore
+        }
+
+        JsonObject jo = waitForOutputFile(outputFile);
+        if (jo != null) {
+            JsonArray arr = (JsonArray) jo.get("routes");
+            for (int i = 0; i < arr.size(); i++) {
+                JsonObject o = (JsonObject) arr.get(i);
+                Row row = new Row();
+                row.location = extractSourceName(o.getString("source"));
+                // if there are 2+ routes in the same source then we would 
have duplicates
+                if (!rows.contains(row)) {
+                    List<JsonObject> lines = o.getCollection("code");
+                    for (JsonObject line : lines) {
+                        Code code = new Code();
+                        code.line = line.getInteger("line");
+                        code.code = line.getString("code");
+                        row.code.add(code);
+                    }
+                    boolean add = true;
+                    if (filter != null) {
+                        String f = filter;
+                        boolean negate = filter.startsWith("-");
+                        if (negate) {
+                            f = f.substring(1);
+                        }
+                        // make filtering easier
+                        if (!f.endsWith("*")) {
+                            f += "*";
+                        }
+                        boolean match = 
PatternHelper.matchPattern(row.location, f);
+                        if (negate) {
+                            match = !match;
+                        }
+                        if (!match) {
+                            add = false;
+                        }
+                    }
+                    if (add) {
+                        rows.add(row);
+                    }
+                }
+            }
+        } else {
+            System.out.println("Response from running Camel with PID " + pid + 
" not received within 5 seconds");
+            return 1;
+        }
+
+        // sort rows
+        rows.sort(this::sortRow);
+
+        if (!rows.isEmpty()) {
+            printSource(rows);
+        }
+
+        // delete output file after use
+        FileUtil.deleteFile(outputFile);
+
+        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.location.compareToIgnoreCase(o2.location) * negate;
+            default:
+                return 0;
+        }
+    }
+
+    protected void printSource(List<Row> rows) {
+        for (Row row : rows) {
+            System.out.println();
+            System.out.printf("Source: %s%n", row.location);
+            
System.out.println("--------------------------------------------------------------------------------");
+            for (int i = 0; i < row.code.size(); i++) {
+                Code code = row.code.get(i);
+                String c = Jsoner.unescape(code.code);
+                System.out.printf("%4d: %s%n", code.line, c);
+            }
+            System.out.println();
+        }
+    }
+
+    protected JsonObject waitForOutputFile(File outputFile) {
+        StopWatch watch = new StopWatch();
+        while (watch.taken() < 5000) {
+            try {
+                // give time for response to be ready
+                Thread.sleep(100);
+
+                if (outputFile.exists()) {
+                    FileInputStream fis = new FileInputStream(outputFile);
+                    String text = IOHelper.loadText(fis);
+                    IOHelper.close(fis);
+                    return (JsonObject) Jsoner.deserialize(text);
+                }
+
+            } catch (Exception e) {
+                // ignore
+            }
+        }
+        return null;
+    }
+
+    public static String extractSourceName(String loc) {
+        loc = stripSourceLocationLineNumber(loc);
+        if (loc != null) {
+            if (loc.contains(":")) {
+                // strip prefix
+                loc = loc.substring(loc.indexOf(':') + 1);
+                // file based such as xml and yaml
+                loc = FileUtil.stripPath(loc);
+            }
+        }
+        return loc;
+    }
+
+    private static class Row {
+        String location;
+        List<Code> code = new ArrayList<>();
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o)
+                return true;
+            if (o == null || getClass() != o.getClass())
+                return false;
+
+            Row row = (Row) o;
+
+            return location.equals(row.location);
+        }
+
+        @Override
+        public int hashCode() {
+            return location.hashCode();
+        }
+    }
+
+    private static class Code {
+        int line;
+        String code;
+    }
+
+}

Reply via email to