You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2022/05/17 11:02:45 UTC
[camel] 02/02: CAMEL-18118: camel-jbang - Linux terminal scripting using pipes
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 dc9ebe6dd1d1e73619dfd1ede2d7bc4e11afa16a
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue May 17 13:00:42 2022 +0200
CAMEL-18118: camel-jbang - Linux terminal scripting using pipes
---
.../modules/ROOT/pages/camel-jbang.adoc | 59 ++++++++++++++++++----
.../dsl/support/RouteBuilderLoaderSupport.java | 55 ++++++++++++++++++++
.../dsl/java/joor/ClassRoutesBuilderLoader.java | 2 +-
.../dsl/java/joor/JavaRoutesBuilderLoader.java | 2 +-
.../dsl/xml/jaxb/JaxbXmlRoutesBuilderLoader.java | 8 +--
.../camel/dsl/yaml/YamlRoutesBuilderLoader.java | 2 +-
.../dsl/yaml/YamlRoutesBuilderLoaderSupport.java | 2 +-
7 files changed, 113 insertions(+), 17 deletions(-)
diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
index 932f7be9a02..6881d7fecf9 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
@@ -206,15 +206,6 @@ This is a groovy route, which you can run with (or use `*`):
camel run simple.groovy
----
-=== Running local Kamelets
-
-You can also use Camel JBang to try local Kamelets, without the need to publish them on GitHub or package them in a jar.
-
-[source,bash]
-----
-camel run --local-kamelet-dir=/path/to/local/kamelets earthquake.yaml
-----
-
==== Downloading routes form GitHub gists
You can also download files from gists easily as shown:
@@ -297,6 +288,56 @@ For example. you can copy this to your clipboard and then run it afterwards:
camel run clipboard.xml
----
+=== Scripting from terminal using pipes
+
+You can also execute a Camel JBang file as a script that can be used for terminal scripting with pipes and filters.
+
+This requires to add the following line in top of the file, for example as in the `upper.yaml` file below:
+
+[source,text]
+----
+///usr/bin/env jbang --quiet camel@apache/camel pipe "$0" "$@" ; exit $?
+
+# Will upper-case the input
+- from:
+ uri: "stream:in"
+ steps:
+ - setBody:
+ simple: "${body.toUpperCase()}"
+ - to: "stream:out"
+----
+
+To be able to execute this as a script, you need to set execute file permission:
+
+[source,bash]
+----
+chmod +x upper.yaml
+----
+
+Then you can then execute this as a script:
+
+[source,bash]
+----
+echo "Hello\nWorld" | ./upper.yaml
+----
+
+Which should output:
+
+[source,text]
+----
+HELLO
+WORLD
+----
+
+=== Running local Kamelets
+
+You can also use Camel JBang to try local Kamelets, without the need to publish them on GitHub or package them in a jar.
+
+[source,bash]
+----
+camel run --local-kamelet-dir=/path/to/local/kamelets earthquake.yaml
+----
+
=== Using platform-http component
When a route is started from `platform-http` then Camel JBang will automatically include a VertX HTTP server
diff --git a/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
index fe67a37cfa7..05aaae5d806 100644
--- a/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
+++ b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
@@ -16,6 +16,12 @@
*/
package org.apache.camel.dsl.support;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -32,6 +38,9 @@ import org.apache.camel.spi.Resource;
import org.apache.camel.spi.RoutesBuilderLoader;
import org.apache.camel.spi.StartupStepRecorder;
import org.apache.camel.support.RoutesBuilderLoaderSupport;
+import org.apache.camel.util.IOHelper;
+
+import static org.apache.camel.util.IOHelper.buffered;
/**
* Base class for {@link RoutesBuilderLoader} implementations.
@@ -115,5 +124,51 @@ public abstract class RouteBuilderLoaderSupport extends RoutesBuilderLoaderSuppo
return builder;
}
+ /**
+ * Gets the input stream to the resource
+ *
+ * @param resource the resource
+ * @return the input stream
+ */
+ protected InputStream resourceInputStream(Resource resource) throws IOException {
+ // load into memory as we need to skip a specific first-line if present
+ String data = loadResource(resource.getInputStream());
+ return new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8));
+ }
+
+
+ /**
+ * Loads {@link RoutesBuilder} from {@link Resource} from the DSL implementation.
+ *
+ * @param resource the resource to be loaded.
+ * @return a {@link RoutesBuilder}
+ */
protected abstract RouteBuilder doLoadRouteBuilder(Resource resource) throws Exception;
+
+ private static String loadResource(InputStream in) throws IOException {
+ StringBuilder builder = new StringBuilder();
+ InputStreamReader isr = new InputStreamReader(in);
+ boolean first = true;
+ try {
+ BufferedReader reader = IOHelper.buffered(isr);
+ while (true) {
+ String line = reader.readLine();
+ if (line != null) {
+ // we need to skip first line if it starts with a special script marker for camel-jbang in pipe mode
+ if (first && line.startsWith("///usr/bin/env jbang --quiet camel@apache/camel pipe")) {
+ line = ""; // use an empty line so line numbers still matches
+ }
+ builder.append(line);
+ builder.append("\n");
+ first = false;
+ } else {
+ break;
+ }
+ }
+ return builder.toString();
+ } finally {
+ IOHelper.close(isr, in);
+ }
+ }
+
}
diff --git a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/ClassRoutesBuilderLoader.java b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/ClassRoutesBuilderLoader.java
index b216f220d3d..c7eb34402f1 100644
--- a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/ClassRoutesBuilderLoader.java
+++ b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/ClassRoutesBuilderLoader.java
@@ -57,7 +57,7 @@ public class ClassRoutesBuilderLoader extends ExtendedRouteBuilderLoaderSupport
Map<String, byte[]> byteCodes = new LinkedHashMap<>();
for (Resource res : resources) {
String className = asClassName(res);
- InputStream is = res.getInputStream();
+ InputStream is = resourceInputStream(res);
if (is != null) {
byte[] code = is.readAllBytes();
byteCodes.put(className, code);
diff --git a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
index c157262cd00..238721e66eb 100644
--- a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
+++ b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
@@ -82,7 +82,7 @@ public class JavaRoutesBuilderLoader extends ExtendedRouteBuilderLoaderSupport {
Map<String, Resource> nameToResource = new HashMap<>();
for (Resource resource : resources) {
- try (InputStream is = resource.getInputStream()) {
+ try (InputStream is = resourceInputStream(resource)) {
if (is == null) {
throw new FileNotFoundException(resource.getLocation());
}
diff --git a/dsl/camel-xml-jaxb-dsl/src/main/java/org/apache/camel/dsl/xml/jaxb/JaxbXmlRoutesBuilderLoader.java b/dsl/camel-xml-jaxb-dsl/src/main/java/org/apache/camel/dsl/xml/jaxb/JaxbXmlRoutesBuilderLoader.java
index f20a0ac144f..48e3453d84d 100644
--- a/dsl/camel-xml-jaxb-dsl/src/main/java/org/apache/camel/dsl/xml/jaxb/JaxbXmlRoutesBuilderLoader.java
+++ b/dsl/camel-xml-jaxb-dsl/src/main/java/org/apache/camel/dsl/xml/jaxb/JaxbXmlRoutesBuilderLoader.java
@@ -50,28 +50,28 @@ public class JaxbXmlRoutesBuilderLoader extends RouteBuilderLoaderSupport {
@Override
public void configure() throws Exception {
// we use configure to load the routes
- try (InputStream is = resource.getInputStream()) {
+ try (InputStream is = resourceInputStream(resource)) {
RouteTemplatesDefinition templates = loadRouteTemplatesDefinition(getCamelContext(), is);
if (templates != null) {
setRouteTemplateCollection(templates);
}
}
- try (InputStream is = resource.getInputStream()) {
+ try (InputStream is = resourceInputStream(resource)) {
TemplatedRoutesDefinition templates = loadTemplatedRoutesDefinition(getCamelContext(), is);
if (templates != null) {
setTemplatedRouteCollection(templates);
}
}
- try (InputStream is = resource.getInputStream()) {
+ try (InputStream is = resourceInputStream(resource)) {
RestsDefinition rests = loadRestsDefinition(getCamelContext(), is);
if (rests != null) {
setRestCollection(rests);
}
}
- try (InputStream is = resource.getInputStream()) {
+ try (InputStream is = resourceInputStream(resource)) {
RoutesDefinition routes = loadRoutesDefinition(getCamelContext(), is);
if (routes != null) {
CamelContextAware.trySetCamelContext(getRouteCollection(), getCamelContext());
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java
index f63b5eb4d71..a6f8cea52ef 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java
@@ -712,7 +712,7 @@ public class YamlRoutesBuilderLoader extends YamlRoutesBuilderLoaderSupport {
throw new FileNotFoundException("Resource not found: " + resource.getLocation());
}
- try (InputStream is = resource.getInputStream()) {
+ try (InputStream is = resourceInputStream(resource)) {
LoadSettings local = LoadSettings.builder().setLabel(resource.getLocation()).build();
final YamlDeserializationContext ctx = newYamlDeserializationContext(local, resource);
final StreamReader reader = new StreamReader(local, new YamlUnicodeReader(is));
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoaderSupport.java b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoaderSupport.java
index de84468b15f..f841970fa22 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoaderSupport.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoaderSupport.java
@@ -76,7 +76,7 @@ public abstract class YamlRoutesBuilderLoaderSupport extends RouteBuilderLoaderS
throw new FileNotFoundException("Resource not found: " + resource.getLocation());
}
- try (InputStream is = resource.getInputStream()) {
+ try (InputStream is = resourceInputStream(resource)) {
// need a local settings because we want the label to be the resource we parse so the parser
// can show parsing errors referring to actual resource file being parsed.
LoadSettings local = LoadSettings.builder().setLabel(resource.getLocation()).build();