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 5f37eca0c9b CAMEL-20421: camel-knative - Only create consumer/producer
http facto… (#13148)
5f37eca0c9b is described below
commit 5f37eca0c9b74078bfc48c1344fe2a76ec02a851
Author: Claus Ibsen <[email protected]>
AuthorDate: Sat Feb 17 20:04:56 2024 +0100
CAMEL-20421: camel-knative - Only create consumer/producer http facto…
(#13148)
CAMEL-20421: camel-knative - Only create consumer/producer http factory
when needed. Make camel-jbang able to detect only when knative consumer is in
use and startup embedded HTTP server to make it work out of the box.
---
.../camel/component/knative/KnativeComponent.java | 88 +++++--------
.../camel/component/knative/KnativeEndpoint.java | 18 +--
.../services/org/apache/camel/dev-console/knative | 2 +
.../component/knative/http/KnativeHttpConsole.java | 141 +++++++++++++++++++++
.../knative/http/KnativeHttpConsumer.java | 14 +-
.../knative/http/KnativeHttpConsumerFactory.java | 9 +-
.../knative/http/KnativeHttpProducer.java | 16 ++-
.../knative/http/KnativeHttpProducerFactory.java | 7 +
.../component/knative/http/KnativeHttpTest.java | 11 --
.../knative/http/KnativeHttpTestSupport.java | 18 +--
.../platform/http/main/MainHttpServer.java | 17 ++-
.../main/java/org/apache/camel/CamelContext.java | 8 ++
.../camel/impl/engine/AbstractCamelContext.java | 6 +
.../camel/cli/connector/LocalCliConnector.java | 8 ++
.../jbang/core/commands/process/ListService.java | 12 +-
.../java/org/apache/camel/main/KameletMain.java | 2 +-
.../DependencyDownloaderClassResolver.java | 25 +++-
.../DependencyDownloaderComponentResolver.java | 39 +-----
.../camel/main/download/MainHttpServerFactory.java | 64 ++++++++++
.../main/download/ResourceResolverListener.java | 29 +++++
20 files changed, 392 insertions(+), 142 deletions(-)
diff --git
a/components/camel-knative/camel-knative-component/src/main/java/org/apache/camel/component/knative/KnativeComponent.java
b/components/camel-knative/camel-knative-component/src/main/java/org/apache/camel/component/knative/KnativeComponent.java
index cc81602bbf6..2b68cd98efb 100644
---
a/components/camel-knative/camel-knative-component/src/main/java/org/apache/camel/component/knative/KnativeComponent.java
+++
b/components/camel-knative/camel-knative-component/src/main/java/org/apache/camel/component/knative/KnativeComponent.java
@@ -55,9 +55,6 @@ public class KnativeComponent extends HealthCheckComponent {
@Metadata
private KnativeConsumerFactory consumerFactory;
- private boolean managedProducer;
- private boolean managedConsumer;
-
public KnativeComponent() {
this(null);
}
@@ -135,6 +132,13 @@ public class KnativeComponent extends HealthCheckComponent
{
return producerFactory;
}
+ public synchronized KnativeProducerFactory getOrCreateProducerFactory()
throws Exception {
+ if (producerFactory == null) {
+ producerFactory = setUpProducerFactory();
+ }
+ return producerFactory;
+ }
+
/**
* The protocol producer factory.
*/
@@ -146,6 +150,13 @@ public class KnativeComponent extends HealthCheckComponent
{
return consumerFactory;
}
+ public synchronized KnativeConsumerFactory getOrCreateConsumerFactory()
throws Exception {
+ if (consumerFactory == null) {
+ consumerFactory = setUpConsumerFactory();
+ }
+ return consumerFactory;
+ }
+
/**
* The protocol consumer factory.
*/
@@ -173,44 +184,19 @@ public class KnativeComponent extends
HealthCheckComponent {
@Override
protected void doInit() throws Exception {
super.doInit();
-
- setUpProducerFactory();
- setUpConsumerFactory();
-
- if (this.producerFactory != null && managedProducer) {
- ServiceHelper.initService(this.producerFactory);
- }
- if (this.consumerFactory != null && managedConsumer) {
- ServiceHelper.initService(this.consumerFactory);
- }
+ ServiceHelper.initService(consumerFactory, producerFactory);
}
@Override
protected void doStart() throws Exception {
super.doStart();
-
- if (this.producerFactory != null && managedProducer) {
- ServiceHelper.startService(this.producerFactory);
- }
- if (this.consumerFactory != null && managedConsumer) {
- ServiceHelper.startService(this.consumerFactory);
- }
-
- if (this.producerFactory == null && this.consumerFactory == null) {
- throw new IllegalStateException("No producer or consumer factory
has been configured");
- }
+ ServiceHelper.startService(consumerFactory, producerFactory);
}
@Override
protected void doStop() throws Exception {
super.doStop();
-
- if (this.producerFactory != null && managedProducer) {
- ServiceHelper.stopService(this.producerFactory);
- }
- if (this.consumerFactory != null && managedConsumer) {
- ServiceHelper.stopService(this.consumerFactory);
- }
+ ServiceHelper.stopService(consumerFactory, producerFactory);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@@ -290,58 +276,44 @@ public class KnativeComponent extends
HealthCheckComponent {
return conf;
}
- private void setUpProducerFactory() throws Exception {
+ private KnativeProducerFactory setUpProducerFactory() throws Exception {
if (producerFactory == null) {
this.producerFactory =
CamelContextHelper.lookup(getCamelContext(), protocol.name(),
KnativeProducerFactory.class);
-
if (this.producerFactory == null) {
this.producerFactory = getCamelContext()
.getCamelContextExtension()
.getBootstrapFactoryFinder(Knative.KNATIVE_TRANSPORT_RESOURCE_PATH)
.newInstance(protocol.name() + "-producer",
KnativeProducerFactory.class)
- .orElse(null);
-
- if (this.producerFactory == null) {
- return;
- }
-
+ .orElseThrow(() -> new IllegalArgumentException(
+ "Cannot create KnativeProducerFactory. Make
sure camel-knative-http JAR is on classpath."));
if (configuration.getTransportOptions() != null) {
setProperties(producerFactory, new
HashMap<>(configuration.getTransportOptions()));
}
-
- this.managedProducer = true;
-
- getCamelContext().addService(this.producerFactory);
+ getCamelContext().addService(this.producerFactory, true, true);
}
-
- LOGGER.info("Using Knative producer factory: {} for protocol: {}",
producerFactory, protocol.name());
+ LOGGER.debug("Using Knative producer factory: {} for protocol:
{}", producerFactory, protocol.name());
}
+
+ return producerFactory;
}
- private void setUpConsumerFactory() throws Exception {
+ private KnativeConsumerFactory setUpConsumerFactory() throws Exception {
if (consumerFactory == null) {
this.consumerFactory =
CamelContextHelper.lookup(getCamelContext(), protocol.name(),
KnativeConsumerFactory.class);
-
if (this.consumerFactory == null) {
this.consumerFactory = getCamelContext()
.getCamelContextExtension()
.getBootstrapFactoryFinder(Knative.KNATIVE_TRANSPORT_RESOURCE_PATH)
.newInstance(protocol.name() + "-consumer",
KnativeConsumerFactory.class)
- .orElse(null);
-
- if (this.consumerFactory == null) {
- return;
- }
+ .orElseThrow(() -> new IllegalArgumentException(
+ "Cannot create KnativeConsumerFactory. Make
sure camel-knative-http JAR is on classpath."));
if (configuration.getTransportOptions() != null) {
setProperties(consumerFactory, new
HashMap<>(configuration.getTransportOptions()));
}
-
- this.managedConsumer = true;
-
- getCamelContext().addService(this.consumerFactory);
+ getCamelContext().addService(this.consumerFactory, true, true);
}
-
- LOGGER.info("Using Knative consumer factory: {} for protocol: {}",
consumerFactory, protocol.name());
+ LOGGER.debug("Using Knative consumer factory: {} for protocol:
{}", consumerFactory, protocol.name());
}
+ return consumerFactory;
}
}
diff --git
a/components/camel-knative/camel-knative-component/src/main/java/org/apache/camel/component/knative/KnativeEndpoint.java
b/components/camel-knative/camel-knative-component/src/main/java/org/apache/camel/component/knative/KnativeEndpoint.java
index 32bbb81aead..afa99dbb03d 100644
---
a/components/camel-knative/camel-knative-component/src/main/java/org/apache/camel/component/knative/KnativeEndpoint.java
+++
b/components/camel-knative/camel-knative-component/src/main/java/org/apache/camel/component/knative/KnativeEndpoint.java
@@ -87,10 +87,12 @@ public class KnativeEndpoint extends DefaultEndpoint {
@Override
public Producer createProducer() throws Exception {
- final KnativeResource service =
lookupServiceDefinition(Knative.EndpointKind.sink);
+ KnativeResource service =
lookupServiceDefinition(Knative.EndpointKind.sink);
+
final Processor ceProcessor = cloudEventProcessor.producer(this,
service);
final Producer producer
- = getComponent().getProducerFactory().createProducer(this,
createTransportConfiguration(service), service);
+ =
getComponent().getOrCreateProducerFactory().createProducer(this,
createTransportConfiguration(service),
+ service);
PropertyBindingSupport.build()
.withCamelContext(getCamelContext())
@@ -106,6 +108,7 @@ public class KnativeEndpoint extends DefaultEndpoint {
@Override
public Consumer createConsumer(Processor processor) throws Exception {
KnativeResource service =
lookupServiceDefinition(Knative.EndpointKind.source);
+
Processor ceProcessor = cloudEventProcessor.consumer(this, service);
Processor replyProcessor
= configuration.isReplyWithCloudEvent() ?
cloudEventProcessor.producer(this, service) : null;
@@ -121,9 +124,12 @@ public class KnativeEndpoint extends DefaultEndpoint {
=
PluginHelper.getProcessorFactory(camelContext).createProcessor(camelContext,
"Pipeline",
new Object[] { list });
- Consumer consumer =
getComponent().getConsumerFactory().createConsumer(this,
+ Consumer consumer =
getComponent().getOrCreateConsumerFactory().createConsumer(this,
createTransportConfiguration(service), service, pipeline);
+ // signal that this path is exposed for knative
+ String path = service.getPath();
+
PropertyBindingSupport.build()
.withCamelContext(camelContext)
.withProperties(configuration.getTransportOptions())
@@ -133,15 +139,9 @@ public class KnativeEndpoint extends DefaultEndpoint {
.bind();
configureConsumer(consumer);
-
return consumer;
}
- @Override
- public boolean isSingleton() {
- return true;
- }
-
public Knative.Type getType() {
return type;
}
diff --git
a/components/camel-knative/camel-knative-http/src/generated/resources/META-INF/services/org/apache/camel/dev-console/knative
b/components/camel-knative/camel-knative-http/src/generated/resources/META-INF/services/org/apache/camel/dev-console/knative
new file mode 100644
index 00000000000..2444b43c411
--- /dev/null
+++
b/components/camel-knative/camel-knative-http/src/generated/resources/META-INF/services/org/apache/camel/dev-console/knative
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.knative.http.KnativeHttpConsole
diff --git
a/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpConsole.java
b/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpConsole.java
new file mode 100644
index 00000000000..324d6745586
--- /dev/null
+++
b/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpConsole.java
@@ -0,0 +1,141 @@
+/*
+ * 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.knative.http;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.camel.Consumer;
+import org.apache.camel.Route;
+import org.apache.camel.Service;
+import org.apache.camel.api.management.ManagedCamelContext;
+import org.apache.camel.spi.annotations.DevConsole;
+import org.apache.camel.support.console.AbstractDevConsole;
+import org.apache.camel.util.StringHelper;
+import org.apache.camel.util.json.JsonObject;
+
+@DevConsole("knative")
+public class KnativeHttpConsole extends AbstractDevConsole {
+
+ public KnativeHttpConsole() {
+ super("camel", "knative", "Knative", "Knative HTTP Service");
+ }
+
+ @Override
+ protected String doCallText(Map<String, Object> options) {
+ StringBuilder sb = new StringBuilder();
+
+ // find if we use MainHttpServer and get its configuration for url
+ ManagedCamelContext mcc =
getCamelContext().getCamelContextExtension().getContextPlugin(ManagedCamelContext.class);
+ if (mcc != null) {
+ String host = null;
+ int port = -1;
+ String path = null;
+ try {
+ Service service = getCamelContext().hasService(s ->
s.getClass().getSimpleName().equals("MainHttpServer"));
+ if (service != null) {
+ MBeanServer mBeanServer =
getCamelContext().getManagementStrategy().getManagementAgent().getMBeanServer();
+ ObjectName on =
getCamelContext().getManagementStrategy().getManagementObjectNameStrategy()
+ .getObjectNameForService(getCamelContext(),
service);
+ host = (String) mBeanServer.getAttribute(on, "Host");
+ port = (int) mBeanServer.getAttribute(on, "Port");
+ path = (String) mBeanServer.getAttribute(on, "Path");
+ }
+ } catch (Exception e) {
+ // ignore
+ }
+
+ List<Consumer> list = getCamelContext().getRoutes()
+ .stream().map(Route::getConsumer)
+ .filter(c ->
KnativeHttpConsumer.class.getName().equals(c.getClass().getName()))
+ .toList();
+
+ for (Consumer c : list) {
+ KnativeHttpConsumer knc = (KnativeHttpConsumer) c;
+ if (host != null) {
+ String p = path != null ? path + "/" + knc.getPath() :
knc.getPath();
+ // remove leading slashes
+ p = StringHelper.removeStartingCharacters(p, '/');
+ sb.append(String.format(" %s://%s:%d/%s\n", "http",
host, port, p));
+ } else {
+ sb.append(String.format(" %s://%s\n", "http",
knc.getPath()));
+ }
+
+ }
+ }
+
+ return sb.toString();
+ }
+
+ @Override
+ protected JsonObject doCallJson(Map<String, Object> options) {
+ JsonObject root = new JsonObject();
+
+ ManagedCamelContext mcc =
getCamelContext().getCamelContextExtension().getContextPlugin(ManagedCamelContext.class);
+ if (mcc != null) {
+ String host = null;
+ int port = -1;
+ String path = null;
+ try {
+ Service service = getCamelContext().hasService(s ->
s.getClass().getSimpleName().equals("MainHttpServer"));
+ if (service != null) {
+ MBeanServer mBeanServer =
getCamelContext().getManagementStrategy().getManagementAgent().getMBeanServer();
+ ObjectName on =
getCamelContext().getManagementStrategy().getManagementObjectNameStrategy()
+ .getObjectNameForService(getCamelContext(),
service);
+ host = (String) mBeanServer.getAttribute(on, "Host");
+ port = (int) mBeanServer.getAttribute(on, "Port");
+ path = (String) mBeanServer.getAttribute(on, "Path");
+ }
+ } catch (Exception e) {
+ // ignore
+ }
+ List<Consumer> list = getCamelContext().getRoutes()
+ .stream().map(Route::getConsumer)
+ .filter(c ->
KnativeHttpConsumer.class.getName().equals(c.getClass().getName()))
+ .toList();
+
+ List<JsonObject> arr = new ArrayList<>();
+ for (Consumer c : list) {
+ KnativeHttpConsumer knc = (KnativeHttpConsumer) c;
+
+ JsonObject jo = new JsonObject();
+ jo.put("protocol", "http");
+ if (host != null) {
+ jo.put("host", host);
+ }
+ if (port != -1) {
+ jo.put("port", port);
+ }
+ String p = path != null ? path + "/" + knc.getPath() :
knc.getPath();
+ // remove leading slashes
+ p = StringHelper.removeStartingCharacters(p, '/');
+ jo.put("path", p);
+ arr.add(jo);
+ }
+ if (!arr.isEmpty()) {
+ root.put("consumers", arr);
+ }
+ }
+
+ return root;
+ }
+
+}
diff --git
a/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpConsumer.java
b/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpConsumer.java
index f7525322b16..19862f53002 100644
---
a/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpConsumer.java
+++
b/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpConsumer.java
@@ -39,6 +39,8 @@ import org.apache.camel.Message;
import org.apache.camel.NoTypeConversionAvailableException;
import org.apache.camel.Processor;
import org.apache.camel.TypeConverter;
+import org.apache.camel.api.management.ManagedAttribute;
+import org.apache.camel.api.management.ManagedResource;
import org.apache.camel.component.knative.spi.KnativeResource;
import org.apache.camel.component.knative.spi.KnativeTransportConfiguration;
import org.apache.camel.spi.HeaderFilterStrategy;
@@ -52,6 +54,7 @@ import org.slf4j.LoggerFactory;
import static org.apache.camel.util.CollectionHelper.appendEntry;
+@ManagedResource(description = "Managed KnativeHttpConsumer")
public class KnativeHttpConsumer extends DefaultConsumer {
private static final Logger LOGGER =
LoggerFactory.getLogger(KnativeHttpConsumer.class);
@@ -60,6 +63,7 @@ public class KnativeHttpConsumer extends DefaultConsumer {
private final KnativeResource resource;
private final Supplier<Router> router;
private final HeaderFilterStrategy headerFilterStrategy;
+ private volatile String path;
private String basePath;
private Route route;
@@ -80,6 +84,12 @@ public class KnativeHttpConsumer extends DefaultConsumer {
this.preallocateBodyBuffer = true;
}
+ @ManagedAttribute(description = "Path for accessing the Knative service")
+ public String getPath() {
+ return path;
+ }
+
+ @ManagedAttribute(description = "Base path")
public String getBasePath() {
return basePath;
}
@@ -88,6 +98,7 @@ public class KnativeHttpConsumer extends DefaultConsumer {
this.basePath = basePath;
}
+ @ManagedAttribute(description = "Maximum body size")
public BigInteger getMaxBodySize() {
return maxBodySize;
}
@@ -96,6 +107,7 @@ public class KnativeHttpConsumer extends DefaultConsumer {
this.maxBodySize = maxBodySize;
}
+ @ManagedAttribute(description = "Preallocate body buffer")
public boolean isPreallocateBodyBuffer() {
return preallocateBodyBuffer;
}
@@ -107,7 +119,7 @@ public class KnativeHttpConsumer extends DefaultConsumer {
@Override
protected void doStart() throws Exception {
if (route == null) {
- String path = resource.getPath();
+ path = resource.getPath();
if (ObjectHelper.isEmpty(path)) {
path = "/";
}
diff --git
a/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpConsumerFactory.java
b/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpConsumerFactory.java
index e751ab3f06a..b05719bb22e 100644
---
a/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpConsumerFactory.java
+++
b/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpConsumerFactory.java
@@ -34,6 +34,13 @@ public class KnativeHttpConsumerFactory extends
ServiceSupport implements CamelC
private Router router;
private CamelContext camelContext;
+ public KnativeHttpConsumerFactory() {
+ }
+
+ public KnativeHttpConsumerFactory(CamelContext camelContext) {
+ this.camelContext = camelContext;
+ }
+
public Router getRouter() {
return router;
}
@@ -71,8 +78,6 @@ public class KnativeHttpConsumerFactory extends
ServiceSupport implements CamelC
/**
* Resolve router from given Camel context if not explicitly set.
KnativeHttpConsumer implementation usually calls
* this method to retrieve the router during service startup phase.
- *
- * @return
*/
private Router lookupRouter() {
if (router == null) {
diff --git
a/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpProducer.java
b/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpProducer.java
index abdeb3e9e0b..68e6bf7504b 100644
---
a/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpProducer.java
+++
b/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpProducer.java
@@ -34,6 +34,8 @@ import org.apache.camel.Exchange;
import org.apache.camel.InvalidPayloadException;
import org.apache.camel.Message;
import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.api.management.ManagedAttribute;
+import org.apache.camel.api.management.ManagedResource;
import org.apache.camel.component.knative.spi.KnativeResource;
import org.apache.camel.spi.HeaderFilterStrategy;
import org.apache.camel.support.DefaultAsyncProducer;
@@ -43,6 +45,7 @@ import org.apache.camel.util.URISupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+@ManagedResource(description = "Managed KnativeHttpProducer")
public class KnativeHttpProducer extends DefaultAsyncProducer {
private static final Logger LOGGER =
LoggerFactory.getLogger(KnativeHttpProducer.class);
@@ -68,23 +71,25 @@ public class KnativeHttpProducer extends
DefaultAsyncProducer {
this.headerFilterStrategy = new KnativeHttpHeaderFilterStrategy();
}
+ @ManagedAttribute(description = "Url for calling the Knative HTTP service")
+ public String getUrl() {
+ return uri;
+ }
+
@Override
public boolean process(Exchange exchange, AsyncCallback callback) {
if (exchange.getMessage().getBody() == null) {
exchange.setException(new IllegalArgumentException("body must not
be null"));
callback.done(true);
-
return true;
}
final byte[] payload;
-
try {
payload = exchange.getMessage().getMandatoryBody(byte[].class);
} catch (InvalidPayloadException e) {
exchange.setException(e);
callback.done(true);
-
return true;
}
@@ -153,17 +158,15 @@ public class KnativeHttpProducer extends
DefaultAsyncProducer {
@Override
protected void doInit() throws Exception {
+ super.doInit();
this.uri = getUrl(serviceDefinition);
this.host = getHost(serviceDefinition);
this.client = WebClient.create(vertx, clientOptions);
-
- super.doInit();
}
@Override
protected void doStop() throws Exception {
super.doStop();
-
if (this.client != null) {
LOGGER.debug("Shutting down client: {}", client);
this.client.close();
@@ -194,7 +197,6 @@ public class KnativeHttpProducer extends
DefaultAsyncProducer {
private String getHost(KnativeResource definition) {
String url = getUrl(definition);
-
try {
return new URL(url).getHost();
} catch (MalformedURLException e) {
diff --git
a/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpProducerFactory.java
b/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpProducerFactory.java
index 7baae79d835..d5cbe2393ef 100644
---
a/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpProducerFactory.java
+++
b/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpProducerFactory.java
@@ -35,6 +35,13 @@ public class KnativeHttpProducerFactory extends
ServiceSupport implements CamelC
private WebClientOptions vertxHttpClientOptions;
private CamelContext camelContext;
+ public KnativeHttpProducerFactory() {
+ }
+
+ public KnativeHttpProducerFactory(CamelContext camelContext) {
+ this.camelContext = camelContext;
+ }
+
public Vertx getVertx() {
return vertx;
}
diff --git
a/components/camel-knative/camel-knative-http/src/test/java/org/apache/camel/component/knative/http/KnativeHttpTest.java
b/components/camel-knative/camel-knative-http/src/test/java/org/apache/camel/component/knative/http/KnativeHttpTest.java
index 68667d417ae..f13821d2832 100644
---
a/components/camel-knative/camel-knative-http/src/test/java/org/apache/camel/component/knative/http/KnativeHttpTest.java
+++
b/components/camel-knative/camel-knative-http/src/test/java/org/apache/camel/component/knative/http/KnativeHttpTest.java
@@ -46,7 +46,6 @@ import org.apache.camel.test.AvailablePortFinder;
import org.apache.camel.util.ObjectHelper;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
@@ -108,16 +107,6 @@ public class KnativeHttpTest {
//
// **************************
- @Test
- void testCreateComponent() {
- context.start();
-
-
assertThat(context.getComponent("knative")).isInstanceOfSatisfying(KnativeComponent.class,
c -> {
-
assertThat(c.getProducerFactory()).isInstanceOf(KnativeHttpProducerFactory.class);
-
assertThat(c.getConsumerFactory()).isInstanceOf(KnativeHttpConsumerFactory.class);
- });
- }
-
void doTestKnativeSource(CloudEvent ce, String basePath, String path)
throws Exception {
KnativeComponent component = configureKnativeComponent(
context,
diff --git
a/components/camel-knative/camel-knative-http/src/test/java/org/apache/camel/component/knative/http/KnativeHttpTestSupport.java
b/components/camel-knative/camel-knative-http/src/test/java/org/apache/camel/component/knative/http/KnativeHttpTestSupport.java
index b79c05ddb90..c5c8a33c1a0 100644
---
a/components/camel-knative/camel-knative-http/src/test/java/org/apache/camel/component/knative/http/KnativeHttpTestSupport.java
+++
b/components/camel-knative/camel-knative-http/src/test/java/org/apache/camel/component/knative/http/KnativeHttpTestSupport.java
@@ -21,15 +21,10 @@ import java.util.List;
import java.util.Map;
import org.apache.camel.CamelContext;
-import org.apache.camel.Consumer;
-import org.apache.camel.Endpoint;
-import org.apache.camel.Processor;
-import org.apache.camel.Producer;
import org.apache.camel.component.cloudevents.CloudEvent;
import org.apache.camel.component.knative.KnativeComponent;
import org.apache.camel.component.knative.spi.KnativeEnvironment;
import org.apache.camel.component.knative.spi.KnativeResource;
-import org.apache.camel.component.knative.spi.KnativeTransportConfiguration;
import org.apache.camel.component.platform.http.PlatformHttpComponent;
import org.apache.camel.component.platform.http.PlatformHttpConstants;
import org.apache.camel.component.platform.http.vertx.VertxPlatformHttpEngine;
@@ -61,19 +56,18 @@ public final class KnativeHttpTestSupport {
KnativeComponent component = context.getComponent("knative",
KnativeComponent.class);
component.setCloudEventsSpecVersion(ce.version());
component.setEnvironment(environment);
- component.setConsumerFactory(new KnativeHttpConsumerFactory() {
+ component.setConsumerFactory(new KnativeHttpConsumerFactory(context) {
@Override
- public Consumer createConsumer(
- Endpoint endpoint, KnativeTransportConfiguration config,
KnativeResource service, Processor processor) {
+ protected void doBuild() throws Exception {
+ super.doBuild();
this.setRouter(VertxPlatformHttpRouter.lookup(context));
- return super.createConsumer(endpoint, config, service,
processor);
}
});
- component.setProducerFactory(new KnativeHttpProducerFactory() {
+ component.setProducerFactory(new KnativeHttpProducerFactory(context) {
@Override
- public Producer createProducer(Endpoint endpoint,
KnativeTransportConfiguration config, KnativeResource service) {
+ protected void doBuild() throws Exception {
+ super.doBuild();
this.setVertx(VertxPlatformHttpRouter.lookup(context).vertx());
- return super.createProducer(endpoint, config, service);
}
});
diff --git
a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/MainHttpServer.java
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/MainHttpServer.java
index 31c4295d1f1..b93e12aff0d 100644
---
a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/MainHttpServer.java
+++
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/MainHttpServer.java
@@ -52,9 +52,10 @@ import io.vertx.ext.web.impl.Utils;
import org.apache.camel.CamelContext;
import org.apache.camel.CamelContextAware;
import org.apache.camel.Exchange;
-import org.apache.camel.NonManagedService;
import org.apache.camel.StartupListener;
import org.apache.camel.StaticService;
+import org.apache.camel.api.management.ManagedAttribute;
+import org.apache.camel.api.management.ManagedResource;
import org.apache.camel.component.platform.http.HttpEndpointModel;
import org.apache.camel.component.platform.http.PlatformHttpComponent;
import
org.apache.camel.component.platform.http.main.jolokia.JolokiaHttpRequestHandlerSupport;
@@ -83,7 +84,8 @@ import org.json.simple.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class MainHttpServer extends ServiceSupport implements
CamelContextAware, StaticService, NonManagedService {
+@ManagedResource(description = "Camel Main Embedded HTTP server")
+public class MainHttpServer extends ServiceSupport implements
CamelContextAware, StaticService {
private static final Logger LOG =
LoggerFactory.getLogger(MainHttpServer.class);
@@ -119,6 +121,7 @@ public class MainHttpServer extends ServiceSupport
implements CamelContextAware,
this.configuration = configuration;
}
+ @ManagedAttribute(description = "Whether dev console is enabled (/q/dev)")
public boolean isDevConsoleEnabled() {
return devConsoleEnabled;
}
@@ -130,10 +133,12 @@ public class MainHttpServer extends ServiceSupport
implements CamelContextAware,
this.devConsoleEnabled = devConsoleEnabled;
}
+ @ManagedAttribute(description = "Whether health check is enabled
(q/health)")
public boolean isHealthCheckEnabled() {
return healthCheckEnabled;
}
+ @ManagedAttribute(description = "Whether Jolokia is enabled (q/jolokia)")
public boolean isJolokiaEnabled() {
return jolokiaEnabled;
}
@@ -152,6 +157,7 @@ public class MainHttpServer extends ServiceSupport
implements CamelContextAware,
this.jolokiaEnabled = jolokiaEnabledEnabled;
}
+ @ManagedAttribute(description = "Whether metrics is enabled (q/metric)")
public boolean isMetricsEnabled() {
return metricsEnabled;
}
@@ -163,6 +169,7 @@ public class MainHttpServer extends ServiceSupport
implements CamelContextAware,
this.metricsEnabled = metricsEnabled;
}
+ @ManagedAttribute(description = "Whether file upload is enabled (only for
development) (q/upload)")
public boolean isUploadEnabled() {
return uploadEnabled;
}
@@ -174,6 +181,7 @@ public class MainHttpServer extends ServiceSupport
implements CamelContextAware,
this.uploadEnabled = uploadEnabled;
}
+ @ManagedAttribute(description = "Directory for upload.")
public String getUploadSourceDir() {
return uploadSourceDir;
}
@@ -185,6 +193,7 @@ public class MainHttpServer extends ServiceSupport
implements CamelContextAware,
this.uploadSourceDir = uploadSourceDir;
}
+ @ManagedAttribute(description = "HTTP server port number")
public int getPort() {
return configuration.getBindPort();
}
@@ -193,6 +202,7 @@ public class MainHttpServer extends ServiceSupport
implements CamelContextAware,
configuration.setBindPort(port);
}
+ @ManagedAttribute(description = "HTTP server hostname")
public String getHost() {
return configuration.getBindHost();
}
@@ -201,6 +211,7 @@ public class MainHttpServer extends ServiceSupport
implements CamelContextAware,
configuration.setBindHost(host);
}
+ @ManagedAttribute(description = "HTTP server base path")
public String getPath() {
return configuration.getPath();
}
@@ -209,6 +220,7 @@ public class MainHttpServer extends ServiceSupport
implements CamelContextAware,
configuration.setPath(path);
}
+ @ManagedAttribute(description = "HTTP server maximum body size")
public Long getMaxBodySize() {
return configuration.getMaxBodySize();
}
@@ -225,6 +237,7 @@ public class MainHttpServer extends ServiceSupport
implements CamelContextAware,
configuration.setSslContextParameters(sslContextParameters);
}
+ @ManagedAttribute(description = "HTTP server using global SSL context
parameters")
public boolean isUseGlobalSslContextParameters() {
return configuration.isUseGlobalSslContextParameters();
}
diff --git a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
index a3cb4bcf99b..1ade841251b 100644
--- a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
+++ b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
@@ -270,6 +270,14 @@ public interface CamelContext extends
CamelContextLifecycle, RuntimeConfiguratio
*/
boolean hasService(Object object);
+ /**
+ * Finds the first service matching the filter
+ *
+ * @param filter the filter
+ * @return the service if found or null if none found
+ */
+ Service hasService(java.util.function.Predicate<Service> filter);
+
/**
* Has the given service type already been added to this CamelContext?
*
diff --git
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
index 118af831990..24cb8e2af08 100644
---
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
+++
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
@@ -38,6 +38,7 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Predicate;
import org.apache.camel.CamelContext;
import org.apache.camel.CamelContextAware;
@@ -1354,6 +1355,11 @@ public abstract class AbstractCamelContext extends
BaseService
return internalServiceManager.hasServices(type);
}
+ @Override
+ public Service hasService(Predicate<Service> filter) {
+ return
internalServiceManager.getServices().stream().filter(filter).findFirst().orElse(null);
+ }
+
@Override
public void deferStartService(Object object, boolean stopOnShutdown) {
internalServiceManager.deferStartService(this, object, stopOnShutdown,
false);
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 df051eb3318..593f8369f71 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
@@ -1112,6 +1112,14 @@ public class LocalCliConnector extends ServiceSupport
implements CliConnector, C
root.put("mllp", json);
}
}
+ // knative is optional
+ dc =
PluginHelper.getDevConsoleResolver(camelContext).lookupDevConsole("knative");
+ if (dc.isPresent()) {
+ JsonObject json = (JsonObject)
dc.get().call(DevConsole.MediaType.JSON);
+ if (json != null) {
+ root.put("knative", json);
+ }
+ }
return root;
}
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListService.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListService.java
index 7cdd1889e03..1e9879f9d31 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListService.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListService.java
@@ -94,6 +94,7 @@ public class ListService extends ProcessWatchCommand {
fetchServices(root, row, "netty", rows);
fetchServices(root, row, "mina", rows);
fetchServices(root, row, "mllp", rows);
+ fetchServices(root, row, "knative", rows);
}
});
@@ -126,7 +127,16 @@ public class ListService extends ProcessWatchCommand {
jo = (JsonObject) o;
row.component = component;
row.protocol = jo.getString("protocol");
- row.service = row.protocol + ":" + jo.getString("host") +
":" + jo.getInteger("port");
+ String p = row.protocol + ":";
+ if (p.startsWith("http")) {
+ // we want double slashes for http protocols
+ p = p + "//";
+ }
+ row.service = p + jo.getString("host") + ":" +
jo.getInteger("port");
+ String path = jo.getString("path");
+ if (path != null) {
+ row.service += "/" + path;
+ }
rows.add(row);
}
}
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 53f73531fa2..ffa1d3ffacb 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
@@ -548,7 +548,7 @@ public class KameletMain extends MainCommandLineSupport {
new DependencyDownloaderStrategy(answer));
// download class-resolver
- ClassResolver classResolver = new
DependencyDownloaderClassResolver(answer, knownDeps);
+ ClassResolver classResolver = new
DependencyDownloaderClassResolver(answer, knownDeps, silent);
answer.setClassResolver(classResolver);
// re-create factory finder with download class-resolver
FactoryFinderResolver ffr =
PluginHelper.getFactoryFinderResolver(answer);
diff --git
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderClassResolver.java
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderClassResolver.java
index fa700f58e60..330728cf27c 100644
---
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderClassResolver.java
+++
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderClassResolver.java
@@ -17,6 +17,8 @@
package org.apache.camel.main.download;
import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
import org.apache.camel.CamelContext;
import org.apache.camel.impl.engine.DefaultClassResolver;
@@ -25,18 +27,25 @@ import org.apache.camel.util.ObjectHelper;
public final class DependencyDownloaderClassResolver extends
DefaultClassResolver {
+ private final List<ResourceResolverListener> resourceResolverListeners =
new ArrayList<>();
private final KnownDependenciesResolver knownDependenciesResolver;
private final DependencyDownloader downloader;
+ private final boolean silent;
public DependencyDownloaderClassResolver(CamelContext camelContext,
- KnownDependenciesResolver
knownDependenciesResolver) {
+ KnownDependenciesResolver
knownDependenciesResolver,
+ boolean silent) {
super(camelContext);
this.downloader = camelContext.hasService(DependencyDownloader.class);
this.knownDependenciesResolver = knownDependenciesResolver;
+ this.silent = silent;
+ this.resourceResolverListeners.add(new KNativeHttpServerFactory());
}
@Override
public InputStream loadResourceAsStream(String uri) {
+ resourceResolverListeners.forEach(l -> l.onLoadResourceAsStream(uri));
+
InputStream answer = null;
try {
answer = super.loadResourceAsStream(uri);
@@ -93,4 +102,18 @@ public final class DependencyDownloaderClassResolver
extends DefaultClassResolve
return answer;
}
+ private class KNativeHttpServerFactory implements ResourceResolverListener
{
+
+ @Override
+ public void onLoadResourceAsStream(String uri) {
+ try {
+ if
("META-INF/services/org/apache/camel/knative/transport/http-consumer".equals(uri))
{
+ MainHttpServerFactory.setupHttpServer(getCamelContext(),
silent);
+ }
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ }
+
}
diff --git
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderComponentResolver.java
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderComponentResolver.java
index 8fd9e2536fb..06bc65678ac 100644
---
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderComponentResolver.java
+++
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderComponentResolver.java
@@ -20,17 +20,11 @@ import java.util.List;
import org.apache.camel.CamelContext;
import org.apache.camel.Component;
-import org.apache.camel.Service;
import org.apache.camel.catalog.CamelCatalog;
import org.apache.camel.catalog.DefaultCamelCatalog;
import org.apache.camel.component.platform.http.PlatformHttpComponent;
-import org.apache.camel.component.platform.http.main.MainHttpServer;
import org.apache.camel.component.stub.StubComponent;
import org.apache.camel.impl.engine.DefaultComponentResolver;
-import org.apache.camel.main.HttpServerConfigurationProperties;
-import org.apache.camel.main.MainConstants;
-import org.apache.camel.main.MainHttpServerFactory;
-import org.apache.camel.main.util.CamelJBangSettingsHelper;
import org.apache.camel.main.util.SuggestSimilarHelper;
import org.apache.camel.tooling.model.ComponentModel;
@@ -75,25 +69,8 @@ public final class DependencyDownloaderComponentResolver
extends DefaultComponen
sc.setShadow(true);
sc.setShadowPattern(stubPattern);
}
- if (answer instanceof PlatformHttpComponent || name.equals("knative"))
{
- // set up a default http server on configured port if not already
done
- MainHttpServer server =
camelContext.hasService(MainHttpServer.class);
- if (server == null) {
- // need to capture that we use a http-server
- HttpServerConfigurationProperties config = new
HttpServerConfigurationProperties(null);
-
CamelJBangSettingsHelper.writeSettingsIfNotExists("camel.jbang.platform-http.port",
- String.valueOf(config.getPort()));
- if (!silent) {
- try {
- // enable http server if not silent
- MainHttpServerFactory factory =
resolveMainHttpServerFactory(camelContext);
- Service httpServer = factory.newHttpServer(config);
- camelContext.addService(httpServer, true, true);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- }
+ if (answer instanceof PlatformHttpComponent) {
+ MainHttpServerFactory.setupHttpServer(camelContext, silent);
}
if (answer == null) {
List<String> suggestion =
SuggestSimilarHelper.didYouMean(catalog.findComponentNames(), name);
@@ -120,16 +97,4 @@ public final class DependencyDownloaderComponentResolver
extends DefaultComponen
return ACCEPTED_STUB_NAMES.contains(name);
}
- private static MainHttpServerFactory
resolveMainHttpServerFactory(CamelContext camelContext) throws Exception {
- // lookup in service registry first
- MainHttpServerFactory answer =
camelContext.getRegistry().findSingleByType(MainHttpServerFactory.class);
- if (answer == null) {
- answer =
camelContext.getCamelContextExtension().getBootstrapFactoryFinder()
- .newInstance(MainConstants.PLATFORM_HTTP_SERVER,
MainHttpServerFactory.class)
- .orElseThrow(() -> new IllegalArgumentException(
- "Cannot find MainHttpServerFactory on classpath.
Add camel-platform-http-main to classpath."));
- }
- return answer;
- }
-
}
diff --git
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MainHttpServerFactory.java
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MainHttpServerFactory.java
new file mode 100644
index 00000000000..8cbba6d1f00
--- /dev/null
+++
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MainHttpServerFactory.java
@@ -0,0 +1,64 @@
+/*
+ * 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.main.download;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Service;
+import org.apache.camel.component.platform.http.main.MainHttpServer;
+import org.apache.camel.main.HttpServerConfigurationProperties;
+import org.apache.camel.main.MainConstants;
+import org.apache.camel.main.util.CamelJBangSettingsHelper;
+
+public class MainHttpServerFactory {
+
+ public static MainHttpServer setupHttpServer(CamelContext camelContext,
boolean silent) {
+ // set up a default http server on configured port if not already done
+ MainHttpServer server = camelContext.hasService(MainHttpServer.class);
+ if (server == null) {
+ // need to capture that we use a http-server
+ HttpServerConfigurationProperties config = new
HttpServerConfigurationProperties(null);
+
CamelJBangSettingsHelper.writeSettingsIfNotExists("camel.jbang.platform-http.port",
+ String.valueOf(config.getPort()));
+ if (!silent) {
+ try {
+ // enable http server if not silent
+ org.apache.camel.main.MainHttpServerFactory factory =
resolveMainHttpServerFactory(camelContext);
+ Service httpServer = factory.newHttpServer(config);
+ camelContext.addService(httpServer, true, true);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ return server;
+ }
+
+ private static org.apache.camel.main.MainHttpServerFactory
resolveMainHttpServerFactory(CamelContext camelContext)
+ throws Exception {
+ // lookup in service registry first
+ org.apache.camel.main.MainHttpServerFactory answer
+ =
camelContext.getRegistry().findSingleByType(org.apache.camel.main.MainHttpServerFactory.class);
+ if (answer == null) {
+ answer =
camelContext.getCamelContextExtension().getBootstrapFactoryFinder()
+ .newInstance(MainConstants.PLATFORM_HTTP_SERVER,
org.apache.camel.main.MainHttpServerFactory.class)
+ .orElseThrow(() -> new IllegalArgumentException(
+ "Cannot find MainHttpServerFactory on classpath.
Add camel-platform-http-main to classpath."));
+ }
+ return answer;
+ }
+
+}
diff --git
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/ResourceResolverListener.java
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/ResourceResolverListener.java
new file mode 100644
index 00000000000..c75b8fb97ee
--- /dev/null
+++
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/ResourceResolverListener.java
@@ -0,0 +1,29 @@
+/*
+ * 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.main.download;
+
+/**
+ * Listener when resources are loaded (eg from src/main/resources)
+ */
+@FunctionalInterface
+public interface ResourceResolverListener {
+
+ /**
+ * Invoked when a resource is attempted to be loaded.
+ */
+ void onLoadResourceAsStream(String uri);
+}