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 6d41186d520481e3c92d22da114f3a739e958649 Author: Claus Ibsen <[email protected]> AuthorDate: Fri Jun 18 21:04:00 2021 +0200 CAMEL-16650: camel-kamelet - Add option to configure location for kamelet template to load from resource. --- .../camel/catalog/docs/kamelet-component.adoc | 2 +- .../kamelet/KameletComponentConfigurer.java | 17 ++-- .../apache/camel/component/kamelet/kamelet.json | 2 +- .../src/main/docs/kamelet-component.adoc | 2 +- .../camel/component/kamelet/KameletComponent.java | 81 +++++------------- .../camel/spi/RouteTemplateLoaderListener.java | 15 ++-- .../dsl/KameletComponentBuilderFactory.java | 12 +-- .../java/org/apache/camel/impl/DefaultModel.java | 46 ++-------- .../apache/camel/support/RouteTemplateHelper.java | 98 ++++++++++++++++++++++ .../modules/ROOT/pages/kamelet-component.adoc | 2 +- .../apache/camel/main/DependencyDownloader.java | 8 +- 11 files changed, 156 insertions(+), 129 deletions(-) diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/kamelet-component.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/kamelet-component.adoc index 69a3580..1f0767e 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/kamelet-component.adoc +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/kamelet-component.adoc @@ -42,7 +42,7 @@ The Kamelet component supports 9 options, which are listed below. | *lazyStartProducer* (producer) | Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...] | *timeout* (producer) | The timeout value to use if block is enabled. | 30000 | long | *autowiredEnabled* (advanced) | Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc. | true | boolean -| *kameletResourceLoaderListener* (advanced) | To plugin a custom listener for when the Kamelet component is loading Kamelets from external resources. | | KameletResourceLoaderListener +| *routeTemplateLoaderListener* (advanced) | *Autowired* To plugin a custom listener for when the Kamelet component is loading Kamelets from external resources. | | RouteTemplateLoaderListener |=== // component options: END diff --git a/components/camel-kamelet/src/generated/java/org/apache/camel/component/kamelet/KameletComponentConfigurer.java b/components/camel-kamelet/src/generated/java/org/apache/camel/component/kamelet/KameletComponentConfigurer.java index ab5be2f..f734ad0 100644 --- a/components/camel-kamelet/src/generated/java/org/apache/camel/component/kamelet/KameletComponentConfigurer.java +++ b/components/camel-kamelet/src/generated/java/org/apache/camel/component/kamelet/KameletComponentConfigurer.java @@ -26,13 +26,13 @@ public class KameletComponentConfigurer extends PropertyConfigurerSupport implem case "block": target.setBlock(property(camelContext, boolean.class, value)); return true; case "bridgeerrorhandler": case "bridgeErrorHandler": target.setBridgeErrorHandler(property(camelContext, boolean.class, value)); return true; - case "kameletresourceloaderlistener": - case "kameletResourceLoaderListener": target.setKameletResourceLoaderListener(property(camelContext, org.apache.camel.component.kamelet.KameletResourceLoaderListener.class, value)); return true; case "lazystartproducer": case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true; case "location": target.setLocation(property(camelContext, java.lang.String.class, value)); return true; case "routeproperties": case "routeProperties": target.setRouteProperties(property(camelContext, java.util.Map.class, value)); return true; + case "routetemplateloaderlistener": + case "routeTemplateLoaderListener": target.setRouteTemplateLoaderListener(property(camelContext, org.apache.camel.spi.RouteTemplateLoaderListener.class, value)); return true; case "templateproperties": case "templateProperties": target.setTemplateProperties(property(camelContext, java.util.Map.class, value)); return true; case "timeout": target.setTimeout(property(camelContext, long.class, value)); return true; @@ -41,6 +41,11 @@ public class KameletComponentConfigurer extends PropertyConfigurerSupport implem } @Override + public String[] getAutowiredNames() { + return new String[]{"routeTemplateLoaderListener"}; + } + + @Override public Class<?> getOptionType(String name, boolean ignoreCase) { switch (ignoreCase ? name.toLowerCase() : name) { case "autowiredenabled": @@ -48,13 +53,13 @@ public class KameletComponentConfigurer extends PropertyConfigurerSupport implem case "block": return boolean.class; case "bridgeerrorhandler": case "bridgeErrorHandler": return boolean.class; - case "kameletresourceloaderlistener": - case "kameletResourceLoaderListener": return org.apache.camel.component.kamelet.KameletResourceLoaderListener.class; case "lazystartproducer": case "lazyStartProducer": return boolean.class; case "location": return java.lang.String.class; case "routeproperties": case "routeProperties": return java.util.Map.class; + case "routetemplateloaderlistener": + case "routeTemplateLoaderListener": return org.apache.camel.spi.RouteTemplateLoaderListener.class; case "templateproperties": case "templateProperties": return java.util.Map.class; case "timeout": return long.class; @@ -71,13 +76,13 @@ public class KameletComponentConfigurer extends PropertyConfigurerSupport implem case "block": return target.isBlock(); case "bridgeerrorhandler": case "bridgeErrorHandler": return target.isBridgeErrorHandler(); - case "kameletresourceloaderlistener": - case "kameletResourceLoaderListener": return target.getKameletResourceLoaderListener(); case "lazystartproducer": case "lazyStartProducer": return target.isLazyStartProducer(); case "location": return target.getLocation(); case "routeproperties": case "routeProperties": return target.getRouteProperties(); + case "routetemplateloaderlistener": + case "routeTemplateLoaderListener": return target.getRouteTemplateLoaderListener(); case "templateproperties": case "templateProperties": return target.getTemplateProperties(); case "timeout": return target.getTimeout(); diff --git a/components/camel-kamelet/src/generated/resources/org/apache/camel/component/kamelet/kamelet.json b/components/camel-kamelet/src/generated/resources/org/apache/camel/component/kamelet/kamelet.json index 48b7c51..2ea411c 100644 --- a/components/camel-kamelet/src/generated/resources/org/apache/camel/component/kamelet/kamelet.json +++ b/components/camel-kamelet/src/generated/resources/org/apache/camel/component/kamelet/kamelet.json @@ -30,7 +30,7 @@ "lazyStartProducer": { "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during star [...] "timeout": { "kind": "property", "displayName": "Timeout", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 30000, "description": "The timeout value to use if block is enabled." }, "autowiredEnabled": { "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which t [...] - "kameletResourceLoaderListener": { "kind": "property", "displayName": "Kamelet Resource Loader Listener", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.kamelet.KameletResourceLoaderListener", "deprecated": false, "autowired": false, "secret": false, "description": "To plugin a custom listener for when the Kamelet component is loading Kamelets from external resources." } + "routeTemplateLoaderListener": { "kind": "property", "displayName": "Route Template Loader Listener", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.RouteTemplateLoaderListener", "deprecated": false, "autowired": true, "secret": false, "description": "To plugin a custom listener for when the Kamelet component is loading Kamelets from external resources." } }, "properties": { "templateId": { "kind": "path", "displayName": "Template Id", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The Route Template ID" }, diff --git a/components/camel-kamelet/src/main/docs/kamelet-component.adoc b/components/camel-kamelet/src/main/docs/kamelet-component.adoc index 69a3580..1f0767e 100644 --- a/components/camel-kamelet/src/main/docs/kamelet-component.adoc +++ b/components/camel-kamelet/src/main/docs/kamelet-component.adoc @@ -42,7 +42,7 @@ The Kamelet component supports 9 options, which are listed below. | *lazyStartProducer* (producer) | Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...] | *timeout* (producer) | The timeout value to use if block is enabled. | 30000 | long | *autowiredEnabled* (advanced) | Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc. | true | boolean -| *kameletResourceLoaderListener* (advanced) | To plugin a custom listener for when the Kamelet component is loading Kamelets from external resources. | | KameletResourceLoaderListener +| *routeTemplateLoaderListener* (advanced) | *Autowired* To plugin a custom listener for when the Kamelet component is loading Kamelets from external resources. | | RouteTemplateLoaderListener |=== // component options: END diff --git a/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/KameletComponent.java b/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/KameletComponent.java index d5c67f1..4cb36ff 100644 --- a/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/KameletComponent.java +++ b/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/KameletComponent.java @@ -27,19 +27,18 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.apache.camel.CamelContext; import org.apache.camel.Endpoint; -import org.apache.camel.ExtendedCamelContext; import org.apache.camel.Processor; import org.apache.camel.RuntimeCamelException; import org.apache.camel.VetoCamelContextStartException; import org.apache.camel.model.ModelCamelContext; import org.apache.camel.model.RouteDefinition; import org.apache.camel.spi.Metadata; -import org.apache.camel.spi.Resource; +import org.apache.camel.spi.RouteTemplateLoaderListener; import org.apache.camel.spi.annotations.Component; import org.apache.camel.support.DefaultComponent; import org.apache.camel.support.LifecycleStrategySupport; +import org.apache.camel.support.RouteTemplateHelper; import org.apache.camel.support.service.ServiceHelper; -import org.apache.camel.util.FileUtil; import org.apache.camel.util.StopWatch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -62,8 +61,8 @@ public class KameletComponent extends DefaultComponent { // active kamelet EIPs private final Map<String, Processor> kameletEips = new ConcurrentHashMap<>(); - @Metadata(label = "advanced") - private KameletResourceLoaderListener kameletResourceLoaderListener; + @Metadata(label = "advanced", autowired = true) + private RouteTemplateLoaderListener routeTemplateLoaderListener; // counter that is used for producers to keep track if any consumer was added/removed since they last checked // this is used for optimization to avoid each producer to get consumer for each message processed @@ -289,15 +288,15 @@ public class KameletComponent extends DefaultComponent { this.location = location; } - public KameletResourceLoaderListener getKameletResourceLoaderListener() { - return kameletResourceLoaderListener; + public RouteTemplateLoaderListener getRouteTemplateLoaderListener() { + return routeTemplateLoaderListener; } /** * To plugin a custom listener for when the Kamelet component is loading Kamelets from external resources. */ - public void setKameletResourceLoaderListener(KameletResourceLoaderListener kameletResourceLoaderListener) { - this.kameletResourceLoaderListener = kameletResourceLoaderListener; + public void setRouteTemplateLoaderListener(RouteTemplateLoaderListener routeTemplateLoaderListener) { + this.routeTemplateLoaderListener = routeTemplateLoaderListener; } int getStateCounter() { @@ -386,7 +385,6 @@ public class KameletComponent extends DefaultComponent { } public void createRouteForEndpoint(KameletEndpoint endpoint) throws Exception { - final ExtendedCamelContext ecc = getCamelContext().adapt(ExtendedCamelContext.class); final ModelCamelContext context = getCamelContext().adapt(ModelCamelContext.class); final String templateId = endpoint.getTemplateId(); final String routeId = endpoint.getRouteId(); @@ -394,64 +392,23 @@ public class KameletComponent extends DefaultComponent { if (context.getRouteTemplateDefinition(templateId) == null && loc != null) { LOGGER.debug("Loading route template={} from {}", templateId, loc); - - boolean found = false; - for (String path : loc.split(",")) { - String name = path; - Resource res = null; - // first try resource as-is if the path has an extension - String ext = FileUtil.onlyExt(path); - if (ext != null) { - res = ecc.getResourceLoader().resolveResource(name); - } - if (res == null || !res.exists()) { - if (!path.endsWith("/")) { - path += "/"; - } - name = path + templateId + ".kamelet.yaml"; - res = ecc.getResourceLoader().resolveResource(name); - } - if (res.exists()) { - try { - if (kameletResourceLoaderListener != null) { - kameletResourceLoaderListener.loadKamelets(res); - } - } catch (Exception e) { - LOGGER.warn("KameletResourceLoaderListener error due to " + e.getMessage() - + ". This exception is ignored", - e); - } - ecc.getRoutesLoader().loadRoutes(res); - found = true; - break; - } - } - if (!found) { - // fallback to old behaviour - String path = loc; - if (!path.endsWith("/")) { - path += "/"; - } - String target = path + templateId + ".kamelet.yaml"; - try { - ecc.getRoutesLoader().loadRoutes( - ecc.getResourceLoader().resolveResource(target)); - } catch (Exception e) { - throw new KameletNotFoundException(templateId, target, e); - } - } + RouteTemplateHelper.loadRouteTemplateFromLocation(getCamelContext(), routeTemplateLoaderListener, templateId, + loc); } LOGGER.debug("Creating route from template={} and id={}", templateId, routeId); + try { + String id = context.addRouteFromTemplate(routeId, templateId, endpoint.getKameletProperties()); + RouteDefinition def = context.getRouteDefinition(id); - final String id = context.addRouteFromTemplate(routeId, templateId, endpoint.getKameletProperties()); - final RouteDefinition def = context.getRouteDefinition(id); + if (!def.isPrepared()) { + context.startRouteDefinitions(Collections.singletonList(def)); + } - if (!def.isPrepared()) { - context.startRouteDefinitions(Collections.singletonList(def)); + LOGGER.debug("Route with id={} created from template={}", id, templateId); + } catch (Exception e) { + throw new KameletNotFoundException(templateId, loc, e); } - - LOGGER.debug("Route with id={} created from template={}", id, templateId); } @Override diff --git a/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/KameletResourceLoaderListener.java b/core/camel-api/src/main/java/org/apache/camel/spi/RouteTemplateLoaderListener.java similarity index 72% rename from components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/KameletResourceLoaderListener.java rename to core/camel-api/src/main/java/org/apache/camel/spi/RouteTemplateLoaderListener.java index 3692a52..d27beff 100644 --- a/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/KameletResourceLoaderListener.java +++ b/core/camel-api/src/main/java/org/apache/camel/spi/RouteTemplateLoaderListener.java @@ -14,23 +14,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.component.kamelet; - -import org.apache.camel.spi.Resource; +package org.apache.camel.spi; /** - * Listener when the Kamelet component is loaing Kamelet(s) from a {@link Resource}. + * Listener when route templates is loaded from a {@link Resource}. * * For example when Kamelets are loaded from YAML files from the classpath, or via github from the Apache Camel Kamelet * Catalog. */ @FunctionalInterface -public interface KameletResourceLoaderListener { +public interface RouteTemplateLoaderListener { /** - * About to load kamelets from the given resource. + * About to load route template (kamelet) from the given resource. * - * @param resource the resource that has kamelets to be loaded + * @param resource the resource that has route templates to be loaded */ - void loadKamelets(Resource resource); + void loadRouteTemplate(Resource resource); + } diff --git a/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/KameletComponentBuilderFactory.java b/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/KameletComponentBuilderFactory.java index f4c2d89..9a5b199 100644 --- a/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/KameletComponentBuilderFactory.java +++ b/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/KameletComponentBuilderFactory.java @@ -202,16 +202,16 @@ public interface KameletComponentBuilderFactory { * Kamelets from external resources. * * The option is a: - * <code>org.apache.camel.component.kamelet.KameletResourceLoaderListener</code> type. + * <code>org.apache.camel.spi.RouteTemplateLoaderListener</code> type. * * Group: advanced * - * @param kameletResourceLoaderListener the value to set + * @param routeTemplateLoaderListener the value to set * @return the dsl builder */ - default KameletComponentBuilder kameletResourceLoaderListener( - org.apache.camel.component.kamelet.KameletResourceLoaderListener kameletResourceLoaderListener) { - doSetProperty("kameletResourceLoaderListener", kameletResourceLoaderListener); + default KameletComponentBuilder routeTemplateLoaderListener( + org.apache.camel.spi.RouteTemplateLoaderListener routeTemplateLoaderListener) { + doSetProperty("routeTemplateLoaderListener", routeTemplateLoaderListener); return this; } } @@ -239,7 +239,7 @@ public interface KameletComponentBuilderFactory { case "lazyStartProducer": ((KameletComponent) component).setLazyStartProducer((boolean) value); return true; case "timeout": ((KameletComponent) component).setTimeout((long) value); return true; case "autowiredEnabled": ((KameletComponent) component).setAutowiredEnabled((boolean) value); return true; - case "kameletResourceLoaderListener": ((KameletComponent) component).setKameletResourceLoaderListener((org.apache.camel.component.kamelet.KameletResourceLoaderListener) value); return true; + case "routeTemplateLoaderListener": ((KameletComponent) component).setRouteTemplateLoaderListener((org.apache.camel.spi.RouteTemplateLoaderListener) value); return true; default: return false; } } diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java index e62511d..453a205 100644 --- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java +++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java @@ -60,14 +60,15 @@ import org.apache.camel.spi.ExchangeFactory; import org.apache.camel.spi.Language; import org.apache.camel.spi.ModelReifierFactory; import org.apache.camel.spi.PropertyConfigurer; -import org.apache.camel.spi.Resource; +import org.apache.camel.spi.RouteTemplateLoaderListener; import org.apache.camel.spi.RouteTemplateParameterSource; import org.apache.camel.spi.ScriptingLanguage; +import org.apache.camel.support.CamelContextHelper; import org.apache.camel.support.PropertyBindingSupport; +import org.apache.camel.support.RouteTemplateHelper; import org.apache.camel.support.ScriptHelper; import org.apache.camel.support.service.ServiceHelper; import org.apache.camel.util.AntPathMatcher; -import org.apache.camel.util.FileUtil; import org.apache.camel.util.ObjectHelper; import org.apache.camel.util.function.Suppliers; @@ -266,7 +267,10 @@ public class DefaultModel implements Model { // and look up again Object location = routeTemplateContext.getParameters().get(RouteTemplateParameterSource.LOCATION); if (location != null) { - loadRouteTemplateFromLocation(routeTemplateId, location.toString()); + RouteTemplateLoaderListener listener + = CamelContextHelper.findByType(getCamelContext(), RouteTemplateLoaderListener.class); + RouteTemplateHelper.loadRouteTemplateFromLocation(getCamelContext(), listener, routeTemplateId, + location.toString()); } for (RouteTemplateDefinition def : routeTemplateDefinitions) { if (routeTemplateId.equals(def.getId())) { @@ -360,42 +364,6 @@ public class DefaultModel implements Model { return def.getId(); } - private void loadRouteTemplateFromLocation(String templateId, String location) throws Exception { - ExtendedCamelContext ecc = getCamelContext().adapt(ExtendedCamelContext.class); - boolean found = false; - for (String path : location.split(",")) { - String name = path; - Resource res = null; - // first try resource as-is if the path has an extension - String ext = FileUtil.onlyExt(path); - if (ext != null) { - res = ecc.getResourceLoader().resolveResource(name); - } - if (res == null || !res.exists()) { - if (!path.endsWith("/")) { - path += "/"; - } - name = path + templateId + ".kamelet.yaml"; - res = ecc.getResourceLoader().resolveResource(name); - } - if (res.exists()) { - ecc.getRoutesLoader().loadRoutes(res); - found = true; - break; - } - } - if (!found) { - // fallback to old behaviour - String path = location; - if (!path.endsWith("/")) { - path += "/"; - } - String target = path + templateId + ".kamelet.yaml"; - ecc.getRoutesLoader().loadRoutes( - ecc.getResourceLoader().resolveResource(target)); - } - } - private void addTemplateBeans(RouteTemplateContext routeTemplateContext, RouteTemplateDefinition target) throws Exception { for (RouteTemplateBeanDefinition b : target.getTemplateBeans()) { final Map<String, Object> props = new HashMap<>(); diff --git a/core/camel-support/src/main/java/org/apache/camel/support/RouteTemplateHelper.java b/core/camel-support/src/main/java/org/apache/camel/support/RouteTemplateHelper.java new file mode 100644 index 0000000..3a7572f --- /dev/null +++ b/core/camel-support/src/main/java/org/apache/camel/support/RouteTemplateHelper.java @@ -0,0 +1,98 @@ +/* + * 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.support; + +import org.apache.camel.CamelContext; +import org.apache.camel.ExtendedCamelContext; +import org.apache.camel.spi.Resource; +import org.apache.camel.spi.RouteTemplateLoaderListener; +import org.apache.camel.util.FileUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Helper for working with route templates. + */ +public final class RouteTemplateHelper { + + private static final Logger LOG = LoggerFactory.getLogger(RouteTemplateHelper.class); + + private RouteTemplateHelper() { + } + + /** + * Loads the route template with the given template id from a given location. After the template is loaded, it is + * automatic added to the {@link CamelContext}. + * + * @param camelContext the camel context + * @param listener optional listener for when a route template is being loaded + * @param templateId the template id + * @param location location of the route template to load as a resource such as from classpath or file system + * @throws Exception is thrown if any kind of error loading the route template + */ + public static void loadRouteTemplateFromLocation( + CamelContext camelContext, RouteTemplateLoaderListener listener, + String templateId, String location) + throws Exception { + if (location == null) { + throw new IllegalArgumentException("Location is empty"); + } + + ExtendedCamelContext ecc = camelContext.adapt(ExtendedCamelContext.class); + boolean found = false; + for (String path : location.split(",")) { + String name = path; + Resource res = null; + // first try resource as-is if the path has an extension + String ext = FileUtil.onlyExt(path); + if (ext != null) { + res = ecc.getResourceLoader().resolveResource(name); + } + if (res == null || !res.exists()) { + if (!path.endsWith("/")) { + path += "/"; + } + name = path + templateId + ".kamelet.yaml"; + res = ecc.getResourceLoader().resolveResource(name); + } + if (res.exists()) { + try { + if (listener != null) { + listener.loadRouteTemplate(res); + } + } catch (Exception e) { + LOG.warn("RouteTemplateLoaderListener error due to " + e.getMessage() + + ". This exception is ignored", + e); + } + ecc.getRoutesLoader().loadRoutes(res); + found = true; + break; + } + } + if (!found) { + // fallback to old behaviour + String path = location; + if (!path.endsWith("/")) { + path += "/"; + } + String target = path + templateId + ".kamelet.yaml"; + ecc.getRoutesLoader().loadRoutes( + ecc.getResourceLoader().resolveResource(target)); + } + } +} diff --git a/docs/components/modules/ROOT/pages/kamelet-component.adoc b/docs/components/modules/ROOT/pages/kamelet-component.adoc index 3ed6c39..a405b0e 100644 --- a/docs/components/modules/ROOT/pages/kamelet-component.adoc +++ b/docs/components/modules/ROOT/pages/kamelet-component.adoc @@ -44,7 +44,7 @@ The Kamelet component supports 9 options, which are listed below. | *lazyStartProducer* (producer) | Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...] | *timeout* (producer) | The timeout value to use if block is enabled. | 30000 | long | *autowiredEnabled* (advanced) | Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc. | true | boolean -| *kameletResourceLoaderListener* (advanced) | To plugin a custom listener for when the Kamelet component is loading Kamelets from external resources. | | KameletResourceLoaderListener +| *routeTemplateLoaderListener* (advanced) | *Autowired* To plugin a custom listener for when the Kamelet component is loading Kamelets from external resources. | | RouteTemplateLoaderListener |=== // component options: END diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/DependencyDownloader.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/DependencyDownloader.java index e6fe851..7a65cbf 100644 --- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/DependencyDownloader.java +++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/DependencyDownloader.java @@ -20,15 +20,15 @@ import org.apache.camel.CamelContext; import org.apache.camel.CamelContextAware; import org.apache.camel.RuntimeCamelException; import org.apache.camel.component.kamelet.KameletComponent; -import org.apache.camel.component.kamelet.KameletResourceLoaderListener; import org.apache.camel.spi.Resource; +import org.apache.camel.spi.RouteTemplateLoaderListener; import org.apache.camel.support.service.ServiceHelper; import org.apache.camel.support.service.ServiceSupport; /** * To automatic downloaded dependencies that Kamelets requires. */ -public final class DependencyDownloader extends ServiceSupport implements CamelContextAware, KameletResourceLoaderListener { +public final class DependencyDownloader extends ServiceSupport implements CamelContextAware, RouteTemplateLoaderListener { private final KameletDependencyDownloader downloader = new KameletDependencyDownloader("yaml"); private CamelContext camelContext; @@ -46,7 +46,7 @@ public final class DependencyDownloader extends ServiceSupport implements CamelC @Override protected void doBuild() throws Exception { KameletComponent kc = camelContext.getComponent("kamelet", KameletComponent.class); - kc.setKameletResourceLoaderListener(this); + kc.setRouteTemplateLoaderListener(this); downloader.setCamelContext(camelContext); ServiceHelper.buildService(downloader); @@ -68,7 +68,7 @@ public final class DependencyDownloader extends ServiceSupport implements CamelC } @Override - public void loadKamelets(Resource resource) { + public void loadRouteTemplate(Resource resource) { if (resource.getLocation().endsWith(".yaml")) { try { downloader.doLoadRouteBuilder(resource);
