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 2023/05/13 09:03:57 UTC
[camel] branch camel-3.x updated: CAMEL-19344: camel-jbang - Upload/delete files in --source-dir via http
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch camel-3.x
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-3.x by this push:
new 416e8faaff1 CAMEL-19344: camel-jbang - Upload/delete files in --source-dir via http
416e8faaff1 is described below
commit 416e8faaff164b29873851171e8ddb30ab292d93
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sat May 13 11:03:27 2023 +0200
CAMEL-19344: camel-jbang - Upload/delete files in --source-dir via http
---
.../modules/ROOT/pages/camel-jbang.adoc | 59 +++++++++++++++++
.../java/org/apache/camel/main/KameletMain.java | 4 ++
.../apache/camel/main/http/VertxHttpServer.java | 74 ++++++++++++++++++++++
3 files changed, 137 insertions(+)
diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
index d7d9dc53fbd..331698b77ba 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
@@ -212,6 +212,65 @@ and reloaded. You can also delete files to remove routes.
NOTE: You cannot use both files and source dir together.
The following is not allowed: `camel run abc.java --source-dir=mycode`.
+==== Uploading files to source directory via HTTP
+
+When running Camel JBang with `--source-dir`, `--console` and `--dev` (reloading) then you can
+change the source files on-the-fly by copying,modifying or deleting the files in the source directory.
+
+This can also be done via HTTP using the `q/upload/:filename` HTTP endpoint using PUT and DELETE verbs.
+
+Given you run Camel JBang with:
+
+[source,bash]
+----
+camel run --source-dir=mycode --console --dev
+----
+
+Then you can upload or modify a source file named `bar.java` you can send a PUT request via curl:
+
+[source,bash]
+----
+curl -X PUT http://0.0.0.0:8080/q/upload/bar.java --data-binary "@bar.java"
+----
+
+Or via:
+
+[source,bash]
+----
+curl -T bar.java http://0.0.0.0:8080/q/upload/bar.java
+----
+
+To send the data via PUT then the file body can be included when using `Content-Type: application/x-www-form-urlencoded`:
+
+For example from a CURL `--ascii-trace`:
+
+[source,text]
+----
+0000: PUT /q/upload/bar.java HTTP/1.1
+0021: Host: 0.0.0.0:8080
+0035: User-Agent: curl/7.87.0
+004e: Accept: */*
+005b: Content-Length: 385
+0070: Content-Type: application/x-www-form-urlencoded
+00a1:
+=> Send data, 385 bytes (0x181)
+0000: // camel-k: language=java..import org.apache.camel.builder.Route
+0040: Builder;..public class bar extends RouteBuilder {.. @Override
+0080: . public void configure() throws Exception {.. // Writ
+00c0: e your routes here, for example:. from("timer:java?period
+0100: ={{time:1000}}"). .setBody(). .simple(
+0140: "XXXCamel from ${routeId}"). .log("${body}");. }.}
+0180: .
+== Info: Mark bundle as not supporting multiuse
+<= Recv header, 17 bytes (0x11)
+0000: HTTP/1.1 200 OK
+<= Recv header, 19 bytes (0x13)
+0000: content-length: 0
+<= Recv header, 2 bytes (0x2)
+0000:
+== Info: Connection #0 to host 0.0.0.0 left intact
+----
+
=== Developer Console
You can enable the developer console, which presents a variety of information to the developer.
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
index c73ef22bca9..4af57aab194 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
@@ -455,6 +455,10 @@ public class KameletMain extends MainCommandLineSupport {
// reloader
String sourceDir = getInitialProperties().getProperty("camel.jbang.sourceDir");
if (sourceDir != null) {
+ if (console || health) {
+ // allow to upload source via http when HTTP console enabled
+ VertxHttpServer.registerUploadSourceDir(answer, sourceDir);
+ }
RouteOnDemandReloadStrategy reloader = new RouteOnDemandReloadStrategy(sourceDir, true);
reloader.setPattern("*");
answer.addService(reloader);
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/http/VertxHttpServer.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/http/VertxHttpServer.java
index ad8be611078..00d51275bad 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/http/VertxHttpServer.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/http/VertxHttpServer.java
@@ -16,6 +16,8 @@
*/
package org.apache.camel.main.http;
+import java.io.File;
+import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
@@ -32,8 +34,10 @@ import java.util.stream.Collectors;
import io.vertx.core.Handler;
import io.vertx.core.http.HttpMethod;
+import io.vertx.ext.web.RequestBody;
import io.vertx.ext.web.Route;
import io.vertx.ext.web.RoutingContext;
+import io.vertx.ext.web.handler.BodyHandler;
import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
import org.apache.camel.RuntimeCamelException;
@@ -51,6 +55,8 @@ import org.apache.camel.health.HealthCheckRegistry;
import org.apache.camel.main.util.CamelJBangSettingsHelper;
import org.apache.camel.spi.CamelEvent;
import org.apache.camel.support.SimpleEventNotifierSupport;
+import org.apache.camel.util.FileUtil;
+import org.apache.camel.util.IOHelper;
import org.apache.camel.util.ObjectHelper;
import org.apache.camel.util.StringHelper;
import org.apache.camel.util.json.JsonObject;
@@ -70,6 +76,7 @@ public final class VertxHttpServer {
private static final AtomicBoolean REGISTERED = new AtomicBoolean();
private static final AtomicBoolean CONSOLE = new AtomicBoolean();
private static final AtomicBoolean HEALTH_CHECK = new AtomicBoolean();
+ private static final AtomicBoolean UPLOAD = new AtomicBoolean();
private VertxHttpServer() {
}
@@ -460,4 +467,71 @@ public final class VertxHttpServer {
return trace;
}
+ public static void registerUploadSourceDir(CamelContext camelContext, String dir) {
+ if (UPLOAD.compareAndSet(false, true)) {
+ doRegisterUploadSourceDir(camelContext, dir);
+ }
+ }
+
+ private static void doRegisterUploadSourceDir(CamelContext context, final String dir) {
+ final Route upload = router.route("/q/upload/:filename")
+ .method(HttpMethod.PUT)
+ // need body handler to handle file uploads
+ .handler(BodyHandler.create(true));
+
+ final Route uploadDelete = router.route("/q/upload/:filename");
+ uploadDelete.method(HttpMethod.DELETE);
+
+ Handler<RoutingContext> handler = new Handler<RoutingContext>() {
+ @Override
+ public void handle(RoutingContext ctx) {
+ String name = ctx.pathParam("filename");
+ if (name == null) {
+ ctx.response().setStatusCode(400);
+ ctx.end();
+ return;
+ }
+
+ int status = 200;
+ boolean delete = HttpMethod.DELETE == ctx.request().method();
+ if (delete) {
+ LOG.info("Deleting file: {}/{}", dir, name);
+ File f = new File(dir, name);
+ if (f.exists() && f.isFile()) {
+ FileUtil.deleteFile(f);
+ }
+ } else {
+ File f = new File(dir, name);
+ boolean exists = f.isFile() && f.exists();
+ LOG.info("{} file: {}/{}", exists ? "Updating" : "Creating", dir, name);
+
+ File tmp = new File(dir, name + ".tmp");
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(tmp, false);
+ RequestBody rb = ctx.body();
+ IOHelper.writeText(rb.asString(), fos);
+
+ FileUtil.renameFileUsingCopy(tmp, f);
+ FileUtil.deleteFile(tmp);
+ } catch (Exception e) {
+ // some kind of error
+ LOG.warn("Error saving file: {}/{} due to: {}", dir, name, e.getMessage(), e);
+ status = 500;
+ } finally {
+ IOHelper.close(fos);
+ FileUtil.deleteFile(tmp);
+ }
+ }
+
+ ctx.response().setStatusCode(status);
+ ctx.end();
+ }
+ };
+ upload.handler(handler);
+ uploadDelete.handler(handler);
+
+ phc.addHttpEndpoint("/q/upload", "PUT,DELETE", null);
+ }
+
}