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 ab02e0bfebb CAMEL-18086: camel-jbang - Uber Jar - Build from fresh
without starting actual components
ab02e0bfebb is described below
commit ab02e0bfebb289213a6dbbd4fb4f35068b4c96f8
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue May 10 10:54:32 2022 +0200
CAMEL-18086: camel-jbang - Uber Jar - Build from fresh without starting
actual components
---
.../org/apache/camel/catalog/components/stub.json | 1 +
.../component/stub/StubComponentConfigurer.java | 25 ++++++++++
.../org/apache/camel/component/stub/stub.json | 1 +
.../apache/camel/component/stub/StubComponent.java | 52 +++++++++++++++++++++
.../camel/component/stub/StubShadowTest.java | 53 ++++++++++++++++++++++
.../apache/camel/dsl/jbang/core/commands/Run.java | 2 +
dsl/camel-kamelet-main/pom.xml | 4 ++
.../DependencyDownloaderComponentResolver.java | 27 +++++++++--
.../java/org/apache/camel/main/KameletMain.java | 29 ++++++++++--
.../org/apache/camel/main/VertxHttpServer.java | 20 ++++----
10 files changed, 199 insertions(+), 15 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/stub.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/stub.json
index 5467e19b32c..2308c91bce0 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/stub.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/stub.json
@@ -22,6 +22,7 @@
"lenientProperties": true
},
"componentProperties": {
+ "shadow": { "kind": "property", "displayName": "Shadow", "group":
"common", "label": "", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "If shadow is enabled then the stub
component will register a shadow endpoint with the actual uri that refers to
the stub endpoint, meaning you can lookup the endpoint via both
stub:kafka:cheese and kafka:cheese." },
"bridgeErrorHandler": { "kind": "property", "displayName": "Bridge Error
Handler", "group": "consumer", "label": "consumer", "required": false, "type":
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "description": "Allows for bridging the
consumer to the Camel routing Error Handler, which mean any exceptions occurred
while the consumer is trying to pickup incoming messages, or the likes, will
now be processed as a me [...]
"concurrentConsumers": { "kind": "property", "displayName": "Concurrent
Consumers", "group": "consumer", "label": "consumer", "required": false,
"type": "integer", "javaType": "int", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 1, "description": "Sets the default number of
concurrent threads processing exchanges." },
"defaultPollTimeout": { "kind": "property", "displayName": "Default Poll
Timeout", "group": "consumer (advanced)", "label": "consumer,advanced",
"required": false, "type": "integer", "javaType": "int", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": 1000, "description": "The
timeout (in milliseconds) used when polling. When a timeout occurs, the
consumer can check whether it is allowed to continue running. Setting a lower
value allows the consumer to react m [...]
diff --git
a/components/camel-stub/src/generated/java/org/apache/camel/component/stub/StubComponentConfigurer.java
b/components/camel-stub/src/generated/java/org/apache/camel/component/stub/StubComponentConfigurer.java
index 33461b4440a..40859597dc7 100644
---
a/components/camel-stub/src/generated/java/org/apache/camel/component/stub/StubComponentConfigurer.java
+++
b/components/camel-stub/src/generated/java/org/apache/camel/component/stub/StubComponentConfigurer.java
@@ -17,5 +17,30 @@ import org.apache.camel.component.vm.VmComponentConfigurer;
@SuppressWarnings("unchecked")
public class StubComponentConfigurer extends VmComponentConfigurer implements
GeneratedPropertyConfigurer, PropertyConfigurerGetter {
+ @Override
+ public boolean configure(CamelContext camelContext, Object obj, String
name, Object value, boolean ignoreCase) {
+ StubComponent target = (StubComponent) obj;
+ switch (ignoreCase ? name.toLowerCase() : name) {
+ case "shadow": target.setShadow(property(camelContext, boolean.class,
value)); return true;
+ default: return super.configure(camelContext, obj, name, value,
ignoreCase);
+ }
+ }
+
+ @Override
+ public Class<?> getOptionType(String name, boolean ignoreCase) {
+ switch (ignoreCase ? name.toLowerCase() : name) {
+ case "shadow": return boolean.class;
+ default: return super.getOptionType(name, ignoreCase);
+ }
+ }
+
+ @Override
+ public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
+ StubComponent target = (StubComponent) obj;
+ switch (ignoreCase ? name.toLowerCase() : name) {
+ case "shadow": return target.isShadow();
+ default: return super.getOptionValue(obj, name, ignoreCase);
+ }
+ }
}
diff --git
a/components/camel-stub/src/generated/resources/org/apache/camel/component/stub/stub.json
b/components/camel-stub/src/generated/resources/org/apache/camel/component/stub/stub.json
index 5467e19b32c..2308c91bce0 100644
---
a/components/camel-stub/src/generated/resources/org/apache/camel/component/stub/stub.json
+++
b/components/camel-stub/src/generated/resources/org/apache/camel/component/stub/stub.json
@@ -22,6 +22,7 @@
"lenientProperties": true
},
"componentProperties": {
+ "shadow": { "kind": "property", "displayName": "Shadow", "group":
"common", "label": "", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "If shadow is enabled then the stub
component will register a shadow endpoint with the actual uri that refers to
the stub endpoint, meaning you can lookup the endpoint via both
stub:kafka:cheese and kafka:cheese." },
"bridgeErrorHandler": { "kind": "property", "displayName": "Bridge Error
Handler", "group": "consumer", "label": "consumer", "required": false, "type":
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "description": "Allows for bridging the
consumer to the Camel routing Error Handler, which mean any exceptions occurred
while the consumer is trying to pickup incoming messages, or the likes, will
now be processed as a me [...]
"concurrentConsumers": { "kind": "property", "displayName": "Concurrent
Consumers", "group": "consumer", "label": "consumer", "required": false,
"type": "integer", "javaType": "int", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 1, "description": "Sets the default number of
concurrent threads processing exchanges." },
"defaultPollTimeout": { "kind": "property", "displayName": "Default Poll
Timeout", "group": "consumer (advanced)", "label": "consumer,advanced",
"required": false, "type": "integer", "javaType": "int", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": 1000, "description": "The
timeout (in milliseconds) used when polling. When a timeout occurs, the
consumer can check whether it is allowed to continue running. Setting a lower
value allows the consumer to react m [...]
diff --git
a/components/camel-stub/src/main/java/org/apache/camel/component/stub/StubComponent.java
b/components/camel-stub/src/main/java/org/apache/camel/component/stub/StubComponent.java
index 6c7e98310fb..0c29225f3dc 100644
---
a/components/camel-stub/src/main/java/org/apache/camel/component/stub/StubComponent.java
+++
b/components/camel-stub/src/main/java/org/apache/camel/component/stub/StubComponent.java
@@ -20,9 +20,15 @@ import java.util.Map;
import java.util.concurrent.BlockingQueue;
import org.apache.camel.Component;
+import org.apache.camel.Endpoint;
import org.apache.camel.Exchange;
+import org.apache.camel.ExtendedCamelContext;
import org.apache.camel.component.seda.BlockingQueueFactory;
import org.apache.camel.component.vm.VmComponent;
+import org.apache.camel.spi.EndpointRegistry;
+import org.apache.camel.spi.EndpointStrategy;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.support.NormalizedUri;
/**
* The <a href="http://camel.apache.org/stub.html">Stub Component</a> is for
stubbing out endpoints while developing or
@@ -34,6 +40,9 @@ import org.apache.camel.component.vm.VmComponent;
@org.apache.camel.spi.annotations.Component("stub")
public class StubComponent extends VmComponent {
+ @Metadata
+ private boolean shadow;
+
public StubComponent() {
}
@@ -59,4 +68,47 @@ public class StubComponent extends VmComponent {
return new StubEndpoint(endpointUri, component, queue,
concurrentConsumers);
}
+ /**
+ * Strategy to resolve the shadow uri to use for the stub endpoints
+ */
+ protected String resolveShadowUri(String uri) {
+ if (uri.startsWith("stub://")) {
+ uri = uri.substring(7);
+ } else if (uri.startsWith("stub:")) {
+ uri = uri.substring(5);
+ }
+ return uri;
+ }
+
+ public boolean isShadow() {
+ return shadow;
+ }
+
+ /**
+ * If shadow is enabled then the stub component will register a shadow
endpoint
+ * with the actual uri that refers to the stub endpoint, meaning you can
lookup
+ * the endpoint via both stub:kafka:cheese and kafka:cheese.
+ */
+ public void setShadow(boolean shadow) {
+ this.shadow = shadow;
+ }
+
+ @Override
+ protected void doInit() throws Exception {
+ super.doInit();
+
+ if (shadow) {
+ final EndpointRegistry registry =
getCamelContext().adapt(ExtendedCamelContext.class).getEndpointRegistry();
+
getCamelContext().adapt(ExtendedCamelContext.class).registerEndpointCallback((uri,
endpoint) -> {
+ String shadowUri = resolveShadowUri(uri);
+ if (!uri.equals(shadowUri)) {
+ NormalizedUri nuri =
NormalizedUri.newNormalizedUri(shadowUri, false);
+ // put the shadow uri directly into the endpoint registry,
+ // so we can lookup the stubbed endpoint using its actual
uri
+ registry.put(nuri, endpoint);
+ }
+ return endpoint;
+ });
+ }
+ }
}
diff --git
a/core/camel-core/src/test/java/org/apache/camel/component/stub/StubShadowTest.java
b/core/camel-core/src/test/java/org/apache/camel/component/stub/StubShadowTest.java
new file mode 100644
index 00000000000..d4aed20c424
--- /dev/null
+++
b/core/camel-core/src/test/java/org/apache/camel/component/stub/StubShadowTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.component.stub;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Endpoint;
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.parallel.ResourceLock;
+
+@ResourceLock("VmComponent")
+public class StubShadowTest extends ContextTestSupport {
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ StubComponent stub = context.getComponent("stub",
StubComponent.class);
+ stub.setShadow(true);
+
+ from("direct:start").to("stub:kafka:foo").to("mock:result");
+ }
+ };
+ }
+
+ @Test
+ public void testShadow() throws InterruptedException {
+ getMockEndpoint("mock:result").expectedBodiesReceived("Hello World");
+
+ template.sendBody("direct:start", "Hello World");
+
+ assertMockEndpointsSatisfied();
+
+ Endpoint se = context.getEndpoint("kafka://foo");
+ assertIsInstanceOf(StubEndpoint.class, se);
+ }
+
+}
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 497dd2a166e..fe3cd40068f 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
@@ -327,6 +327,8 @@ class Run implements Callable<Integer> {
}
if (silentRun) {
+ // enable stub in silent mode so we do not use real components
+ main.setStub(true);
// do not run for very long in silent run
main.addInitialProperty("camel.main.autoStartup", "false");
main.addInitialProperty("camel.main.durationMaxSeconds", "1");
diff --git a/dsl/camel-kamelet-main/pom.xml b/dsl/camel-kamelet-main/pom.xml
index dde0376df40..8341f713c2c 100644
--- a/dsl/camel-kamelet-main/pom.xml
+++ b/dsl/camel-kamelet-main/pom.xml
@@ -84,6 +84,10 @@
<groupId>org.apache.camel</groupId>
<artifactId>camel-platform-http-vertx</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-stub</artifactId>
+ </dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-timer</artifactId>
diff --git
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/DependencyDownloaderComponentResolver.java
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/DependencyDownloaderComponentResolver.java
index 3f681082acc..db1ef258690 100644
---
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/DependencyDownloaderComponentResolver.java
+++
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/DependencyDownloaderComponentResolver.java
@@ -30,11 +30,15 @@ import org.apache.camel.tooling.model.ComponentModel;
*/
final class DependencyDownloaderComponentResolver extends
DefaultComponentResolver implements CamelContextAware {
+ private static final String ACCEPTED_STUB_NAMES =
"stub,bean,class,kamelet,rest,rest-api,platform-http,vertx-http";
+
private final CamelCatalog catalog = new DefaultCamelCatalog();
private CamelContext camelContext;
+ private boolean stub;
- public DependencyDownloaderComponentResolver(CamelContext camelContext) {
+ public DependencyDownloaderComponentResolver(CamelContext camelContext,
boolean stub) {
this.camelContext = camelContext;
+ this.stub = stub;
}
@Override
@@ -53,15 +57,32 @@ final class DependencyDownloaderComponentResolver extends
DefaultComponentResolv
if (model != null &&
!DownloaderHelper.alreadyOnClasspath(camelContext, model.getArtifactId(),
model.getVersion())) {
DownloaderHelper.downloadDependency(camelContext,
model.getGroupId(), model.getArtifactId(), model.getVersion());
}
- Component answer = super.resolveComponent(name, context);
+
+ Component answer;
+ boolean accept = accept(name);
+ if (accept) {
+ answer = super.resolveComponent(name, context);
+ } else {
+ answer = super.resolveComponent("stub", context);
+ }
if (answer instanceof PlatformHttpComponent) {
// setup a default http server on port 8080 if not already done
VertxHttpServer.phc = (PlatformHttpComponent) answer;
- VertxHttpServer.registerServer(camelContext);
+ VertxHttpServer.registerServer(camelContext, stub);
}
return answer;
}
+ private boolean accept(String name) {
+ // kamelet component must not be stubbed
+ if (!stub) {
+ return true;
+ }
+
+ // we are stubbing but need to accept the following
+ return ACCEPTED_STUB_NAMES.contains(name);
+ }
+
}
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 ce4e8500297..4d4f4345aaa 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
@@ -39,6 +39,7 @@ public class KameletMain extends MainCommandLineSupport {
protected final MainRegistry registry = new MainRegistry();
private boolean download = true;
+ private boolean stub;
private DownloadListener downloadListener;
private GroovyClassLoader groovyClassLoader;
@@ -116,6 +117,18 @@ public class KameletMain extends MainCommandLineSupport {
this.download = download;
}
+ public boolean isStub() {
+ return stub;
+ }
+
+ /**
+ * Whether to use stub endpoints instead of creating the actual endpoints.
+ * This allows to simulate using real components but run without them on
the classpath.
+ */
+ public void setStub(boolean stub) {
+ this.stub = stub;
+ }
+
public DownloadListener getDownloadListener() {
return downloadListener;
}
@@ -202,6 +215,10 @@ public class KameletMain extends MainCommandLineSupport {
if (download) {
answer.setApplicationContextClassLoader(createApplicationContextClassLoader());
}
+ if (stub) {
+ // turn off auto-wiring when running in stub mode
+ mainConfigurationProperties.setAutowiredEnabled(false);
+ }
// register download listener
if (downloadListener != null) {
@@ -222,12 +239,12 @@ public class KameletMain extends MainCommandLineSupport {
// embed HTTP server if port is specified
Object port =
getInitialProperties().get("camel.jbang.platform-http.port");
if (port != null) {
- VertxHttpServer.registerServer(answer,
Integer.parseInt(port.toString()));
+ VertxHttpServer.registerServer(answer,
Integer.parseInt(port.toString()), stub);
}
boolean console =
"true".equals(getInitialProperties().get("camel.jbang.console"));
if (console && port == null) {
// use default port 8080 if console is enabled
- VertxHttpServer.registerServer(answer, 8080);
+ VertxHttpServer.registerServer(answer, 8080, stub);
}
if (console) {
// turn on developer console
@@ -240,7 +257,7 @@ public class KameletMain extends MainCommandLineSupport {
boolean health =
"true".equals(getInitialProperties().get("camel.jbang.health"));
if (health && port == null) {
// use default port 8080 if console is enabled
- VertxHttpServer.registerServer(answer, 8080);
+ VertxHttpServer.registerServer(answer, 8080, stub);
}
if (health) {
VertxHttpServer.registerHealthCheck(answer);
@@ -275,7 +292,7 @@ public class KameletMain extends MainCommandLineSupport {
answer.getRegistry().bind(DependencyDownloaderStrategy.class.getName(),
new DependencyDownloaderStrategy(answer));
answer.setClassResolver(new
DependencyDownloaderClassResolver(answer, known));
- answer.setComponentResolver(new
DependencyDownloaderComponentResolver(answer));
+ answer.setComponentResolver(new
DependencyDownloaderComponentResolver(answer, stub));
answer.setDataFormatResolver(new
DependencyDownloaderDataFormatResolver(answer));
answer.setLanguageResolver(new
DependencyDownloaderLanguageResolver(answer));
answer.addService(new DependencyDownloaderKamelet());
@@ -327,6 +344,10 @@ public class KameletMain extends MainCommandLineSupport {
addInitialProperty("camel.component.kamelet.location", location);
addInitialProperty("camel.component.rest.consumerComponentName",
"platform-http");
addInitialProperty("camel.component.rest.producerComponentName",
"vertx-http");
+ if (stub) {
+ // enable shadow mode on stub component
+ addInitialProperty("camel.component.stub.shadow", "true");
+ }
}
protected String startupInfo() {
diff --git
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/VertxHttpServer.java
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/VertxHttpServer.java
index 877bf93c816..b84bb2d2ce1 100644
---
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/VertxHttpServer.java
+++
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/VertxHttpServer.java
@@ -68,19 +68,26 @@ public final class VertxHttpServer {
private VertxHttpServer() {
}
- public static void registerServer(CamelContext camelContext) {
+ public static void registerServer(CamelContext camelContext, boolean stub)
{
if (REGISTERED.compareAndSet(false, true)) {
- doRegisterServer(camelContext, 8080);
+ doRegisterServer(camelContext, 8080, stub);
}
}
- public static void registerServer(CamelContext camelContext, int port) {
+ public static void registerServer(CamelContext camelContext, int port,
boolean stub) {
if (REGISTERED.compareAndSet(false, true)) {
- doRegisterServer(camelContext, port);
+ doRegisterServer(camelContext, port, stub);
}
}
- private static void doRegisterServer(CamelContext camelContext, int port) {
+ private static void doRegisterServer(CamelContext camelContext, int port,
boolean stub) {
+ // need to capture we use http-server
+
CamelJBangSettingsHelper.writeSettings("camel.jbang.platform-http.port", "" +
port);
+
+ if (stub) {
+ return;
+ }
+
try {
VertxPlatformHttpServerConfiguration config = new
VertxPlatformHttpServerConfiguration();
config.setPort(port);
@@ -92,9 +99,6 @@ public final class VertxHttpServer {
phc = camelContext.getComponent("platform-http",
PlatformHttpComponent.class);
}
- // need to capture we use http-server
-
CamelJBangSettingsHelper.writeSettings("camel.jbang.platform-http.port", "" +
port);
-
// after camel is started then add event notifier
camelContext.addStartupListener(new StartupListener() {
@Override