This is an automated email from the ASF dual-hosted git repository. ppalaga pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git
commit 78f03720944ce50481a9b63fe8b70cdb78a5443e Author: Luca Burgazzoli <[email protected]> AuthorDate: Tue Jun 8 21:44:52 2021 +0200 core: sync BaseModel and FastCamelContext with Camel main --- .../org/apache/camel/quarkus/core/BaseModel.java | 192 ++++++++++++++++++++- .../camel/quarkus/core/FastCamelContext.java | 106 +++++++++++- integration-tests/kamelet/pom.xml | 4 + .../component/kamelet/it/KameletResource.java | 8 + .../component/kamelet/it/KameletRoutes.java | 23 +++ .../quarkus/component/kamelet/it/KameletTest.java | 19 ++ 6 files changed, 338 insertions(+), 14 deletions(-) diff --git a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/BaseModel.java b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/BaseModel.java index 4233ddc..410c8d6 100644 --- a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/BaseModel.java +++ b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/BaseModel.java @@ -23,13 +23,19 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.StringJoiner; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import org.apache.camel.CamelContext; +import org.apache.camel.Component; +import org.apache.camel.Exchange; +import org.apache.camel.Expression; import org.apache.camel.ExtendedCamelContext; import org.apache.camel.FailedToCreateRouteFromTemplateException; +import org.apache.camel.NoSuchBeanException; +import org.apache.camel.PropertyBindingException; import org.apache.camel.RouteTemplateContext; import org.apache.camel.impl.DefaultModelReifierFactory; import org.apache.camel.model.DataFormatDefinition; @@ -45,15 +51,25 @@ import org.apache.camel.model.Resilience4jConfigurationDefinition; import org.apache.camel.model.RouteDefinition; import org.apache.camel.model.RouteDefinitionHelper; import org.apache.camel.model.RouteFilters; +import org.apache.camel.model.RouteTemplateBeanDefinition; import org.apache.camel.model.RouteTemplateDefinition; import org.apache.camel.model.RouteTemplateParameterDefinition; import org.apache.camel.model.cloud.ServiceCallConfigurationDefinition; import org.apache.camel.model.rest.RestDefinition; import org.apache.camel.model.transformer.TransformerDefinition; import org.apache.camel.model.validator.ValidatorDefinition; +import org.apache.camel.spi.ExchangeFactory; +import org.apache.camel.spi.Language; import org.apache.camel.spi.ModelReifierFactory; import org.apache.camel.spi.NodeIdFactory; +import org.apache.camel.spi.PropertyConfigurer; +import org.apache.camel.spi.ScriptingLanguage; +import org.apache.camel.support.PropertyBindingSupport; +import org.apache.camel.support.ScriptHelper; +import org.apache.camel.support.service.ServiceHelper; import org.apache.camel.util.AntPathMatcher; +import org.apache.camel.util.ObjectHelper; +import org.apache.camel.util.function.Suppliers; public abstract class BaseModel implements Model { @@ -218,11 +234,6 @@ public abstract class BaseModel implements Model { throw new IllegalArgumentException("Cannot find RouteTemplate with id " + routeTemplateId); } - // apply configurer if any present - if (target.getConfigurer() != null) { - target.getConfigurer().accept(routeTemplateContext); - } - final Map<String, Object> prop = new HashMap<>(); // include default values first from the template (and validate that we have inputs for all required parameters) if (target.getTemplateParameters() != null) { @@ -232,8 +243,8 @@ public abstract class BaseModel implements Model { if (temp.getDefaultValue() != null) { prop.put(temp.getName(), temp.getDefaultValue()); } else { - // this is a required parameter do we have that as input - if (!routeTemplateContext.getParameters().containsKey(temp.getName())) { + if (temp.isRequired() && !routeTemplateContext.getParameters().containsKey(temp.getName())) { + // this is a required parameter which is missing templatesBuilder.add(temp.getName()); } } @@ -241,14 +252,23 @@ public abstract class BaseModel implements Model { if (templatesBuilder.length() > 0) { throw new IllegalArgumentException( "Route template " + routeTemplateId + " the following mandatory parameters must be provided: " - + templatesBuilder.toString()); + + templatesBuilder); } } - // then override with user parameters + // then override with user parameters part 1 if (routeTemplateContext.getParameters() != null) { prop.putAll(routeTemplateContext.getParameters()); } + // route template context should include default template parameters from the target route template + // so it has all parameters available + if (target.getTemplateParameters() != null) { + for (RouteTemplateParameterDefinition temp : target.getTemplateParameters()) { + if (!routeTemplateContext.getParameters().containsKey(temp.getName()) && temp.getDefaultValue() != null) { + routeTemplateContext.setParameter(temp.getName(), temp.getDefaultValue()); + } + } + } RouteTemplateDefinition.Converter converter = RouteTemplateDefinition.Converter.DEFAULT_CONVERTER; @@ -275,6 +295,15 @@ public abstract class BaseModel implements Model { def.setTemplateParameters(prop); def.setRouteTemplateContext(routeTemplateContext); + // setup local beans + if (target.getTemplateBeans() != null) { + addTemplateBeans(routeTemplateContext, target); + } + + if (target.getConfigurer() != null) { + routeTemplateContext.setConfigurer(target.getConfigurer()); + } + // assign ids to the routes and validate that the id's are all unique String duplicate = RouteDefinitionHelper.validateUniqueIds(def, routeDefinitions); if (duplicate != null) { @@ -286,6 +315,96 @@ public abstract class BaseModel implements Model { return def.getId(); } + private void addTemplateBeans(RouteTemplateContext routeTemplateContext, RouteTemplateDefinition target) throws Exception { + for (RouteTemplateBeanDefinition b : target.getTemplateBeans()) { + final Map<String, Object> props = new HashMap<>(); + if (b.getProperties() != null) { + b.getProperties().forEach(p -> props.put(p.getKey(), p.getValue())); + } + if (b.getBeanSupplier() != null) { + if (props.isEmpty()) { + // bean class is optional for supplier + if (b.getBeanClass() != null) { + routeTemplateContext.bind(b.getName(), b.getBeanClass(), b.getBeanSupplier()); + } else { + routeTemplateContext.bind(b.getName(), b.getBeanSupplier()); + } + } + } else if (b.getScript() != null) { + final String script = b.getScript().getScript(); + final Language lan = camelContext.resolveLanguage(b.getType()); + final Class<?> clazz = b.getBeanType() != null + ? camelContext.getClassResolver().resolveMandatoryClass(b.getBeanType()) + : b.getBeanClass() != null ? b.getBeanClass() : Object.class; + final ScriptingLanguage slan = lan instanceof ScriptingLanguage ? (ScriptingLanguage) lan : null; + if (slan != null) { + // scripting language should be evaluated with route template context as binding + // and memorize so the script is only evaluated once and the local bean is the same + // if a route template refers to the local bean multiple times + routeTemplateContext.bind(b.getName(), clazz, Suppliers.memorize(() -> { + Map<String, Object> bindings = new HashMap<>(); + // use rtx as the short-hand name, as context would imply its CamelContext + bindings.put("rtc", routeTemplateContext); + Object local = slan.evaluate(script, bindings, clazz); + if (!props.isEmpty()) { + setPropertiesOnTarget(camelContext, local, props); + } + return local; + })); + } else { + // exchange based languages needs a dummy exchange to be evaluated + // and memorize so the script is only evaluated once and the local bean is the same + // if a route template refers to the local bean multiple times + routeTemplateContext.bind(b.getName(), clazz, Suppliers.memorize(() -> { + ExchangeFactory ef = camelContext.adapt(ExtendedCamelContext.class).getExchangeFactory(); + Exchange dummy = ef.create(false); + try { + String text = ScriptHelper.resolveOptionalExternalScript(camelContext, dummy, script); + if (text != null) { + Expression exp = lan.createExpression(text); + Object local = exp.evaluate(dummy, clazz); + if (!props.isEmpty()) { + setPropertiesOnTarget(camelContext, local, props); + } + return local; + } else { + return null; + } + } finally { + ef.release(dummy); + } + })); + } + } else if (b.getBeanClass() != null || b.getType() != null && b.getType().startsWith("#class:")) { + Class<?> clazz = b.getBeanClass() != null + ? b.getBeanClass() : camelContext.getClassResolver().resolveMandatoryClass(b.getType().substring(7)); + // we only have the bean class so we use that to create a new bean via the injector + // and memorize so the bean is only created once and the local bean is the same + // if a route template refers to the local bean multiple times + routeTemplateContext.bind(b.getName(), clazz, + Suppliers.memorize(() -> { + Object local = camelContext.getInjector().newInstance(clazz); + if (!props.isEmpty()) { + setPropertiesOnTarget(camelContext, local, props); + } + return local; + })); + } else if (b.getType() != null && b.getType().startsWith("#type:")) { + Class<?> clazz = camelContext.getClassResolver().resolveMandatoryClass(b.getType().substring(6)); + Set<?> found = getCamelContext().getRegistry().findByType(clazz); + if (found == null || found.isEmpty()) { + throw new NoSuchBeanException(null, clazz.getName()); + } else if (found.size() > 1) { + throw new NoSuchBeanException( + "Found " + found.size() + " beans of type: " + clazz + ". Only one bean expected."); + } else { + // do not set properties when using #type as it uses an existing shared bean + routeTemplateContext.bind(b.getName(), clazz, found.iterator().next()); + } + } + } + } + @Override public synchronized List<RestDefinition> getRestDefinitions() { return restDefinitions; @@ -526,4 +645,59 @@ public abstract class BaseModel implements Model { return camelContext.isStarted() && !camelContext.isStarting(); } + private static void setPropertiesOnTarget(CamelContext context, Object target, Map<String, Object> properties) { + ObjectHelper.notNull(context, "context"); + ObjectHelper.notNull(target, "target"); + ObjectHelper.notNull(properties, "properties"); + + if (target instanceof CamelContext) { + throw new UnsupportedOperationException("Configuring the Camel Context is not supported"); + } + + PropertyConfigurer configurer = null; + if (target instanceof Component) { + // the component needs to be initialized to have the configurer ready + ServiceHelper.initService(target); + configurer = ((Component) target).getComponentPropertyConfigurer(); + } + + if (configurer == null) { + // see if there is a configurer for it + configurer = context.adapt(ExtendedCamelContext.class) + .getConfigurerResolver() + .resolvePropertyConfigurer(target.getClass().getSimpleName(), context); + } + + try { + PropertyBindingSupport.build() + .withMandatory(true) + .withRemoveParameters(false) + .withConfigurer(configurer) + .withIgnoreCase(true) + .withFlattenProperties(true) + .bind(context, target, properties); + } catch (PropertyBindingException e) { + String key = e.getOptionKey(); + if (key == null) { + String prefix = e.getOptionPrefix(); + if (prefix != null && !prefix.endsWith(".")) { + prefix = "." + prefix; + } + + key = prefix != null + ? prefix + "." + e.getPropertyName() + : e.getPropertyName(); + } + + // enrich the error with more precise details with option prefix and key + throw new PropertyBindingException( + e.getTarget(), + e.getPropertyName(), + e.getValue(), + null, + key, + e.getCause()); + } + } + } diff --git a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/FastCamelContext.java b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/FastCamelContext.java index 4fafa76..dda025f 100644 --- a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/FastCamelContext.java +++ b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/FastCamelContext.java @@ -19,6 +19,7 @@ package org.apache.camel.quarkus.core; import java.io.IOException; import java.io.InputStream; import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -30,11 +31,13 @@ import org.apache.camel.CatalogCamelContext; import org.apache.camel.Component; import org.apache.camel.Endpoint; import org.apache.camel.Expression; +import org.apache.camel.ExtendedCamelContext; import org.apache.camel.FailedToStartRouteException; import org.apache.camel.Predicate; import org.apache.camel.Processor; import org.apache.camel.Route; import org.apache.camel.RouteTemplateContext; +import org.apache.camel.StartupStep; import org.apache.camel.TypeConverter; import org.apache.camel.ValueHolder; import org.apache.camel.builder.AdviceWith; @@ -87,6 +90,7 @@ import org.apache.camel.model.Model; import org.apache.camel.model.ModelCamelContext; import org.apache.camel.model.ModelLifecycleStrategy; import org.apache.camel.model.ProcessorDefinition; +import org.apache.camel.model.ProcessorDefinitionHelper; import org.apache.camel.model.Resilience4jConfigurationDefinition; import org.apache.camel.model.RouteDefinition; import org.apache.camel.model.RouteDefinitionHelper; @@ -100,7 +104,6 @@ import org.apache.camel.processor.DefaultAnnotationBasedProcessorFactory; import org.apache.camel.processor.DefaultDeferServiceFactory; import org.apache.camel.processor.DefaultInternalProcessorFactory; import org.apache.camel.processor.DefaultProcessorFactory; -import org.apache.camel.reifier.RouteReifier; import org.apache.camel.reifier.errorhandler.ErrorHandlerReifier; import org.apache.camel.reifier.language.ExpressionReifier; import org.apache.camel.reifier.transformer.TransformerReifier; @@ -132,6 +135,7 @@ import org.apache.camel.spi.InterceptEndpointFactory; import org.apache.camel.spi.InternalProcessorFactory; import org.apache.camel.spi.Language; import org.apache.camel.spi.LanguageResolver; +import org.apache.camel.spi.LocalBeanRepositoryAware; import org.apache.camel.spi.ManagementNameStrategy; import org.apache.camel.spi.MessageHistoryFactory; import org.apache.camel.spi.ModelJAXBContextFactory; @@ -152,6 +156,7 @@ import org.apache.camel.spi.RouteController; import org.apache.camel.spi.RouteFactory; import org.apache.camel.spi.RoutesLoader; import org.apache.camel.spi.ShutdownStrategy; +import org.apache.camel.spi.StartupStepRecorder; import org.apache.camel.spi.StreamCachingStrategy; import org.apache.camel.spi.Tracer; import org.apache.camel.spi.Transformer; @@ -165,12 +170,19 @@ import org.apache.camel.spi.ValidatorRegistry; import org.apache.camel.spi.XMLRoutesDefinitionLoader; import org.apache.camel.support.CamelContextHelper; import org.apache.camel.support.DefaultUuidGenerator; +import org.apache.camel.support.LocalBeanRegistry; import org.apache.camel.support.NormalizedUri; import org.apache.camel.support.ResolverHelper; +import org.apache.camel.support.SimpleUuidGenerator; import org.apache.camel.util.IOHelper; import org.apache.camel.util.ObjectHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class FastCamelContext extends AbstractCamelContext implements CatalogCamelContext, ModelCamelContext { + private static final Logger LOG = LoggerFactory.getLogger(FastCamelContext.class); + private static final UuidGenerator UUID = new SimpleUuidGenerator(); + private final String version; private final ModelToXMLDumper modelDumper; private Model model; @@ -933,8 +945,11 @@ public class FastCamelContext extends AbstractCamelContext implements CatalogCam model.setModelReifierFactory(modelReifierFactory); } - @Override public void startRouteDefinitions(List<RouteDefinition> routeDefinitions) throws Exception { + if (model == null && isLightweight()) { + throw new IllegalStateException("Access to model not supported in lightweight mode"); + } + // indicate we are staring the route using this thread so // we are able to query this if needed boolean alreadyStartingRoutes = isStartingRoutes(); @@ -943,22 +958,88 @@ public class FastCamelContext extends AbstractCamelContext implements CatalogCam } PropertiesComponent pc = getCamelContextReference().getPropertiesComponent(); + // route templates supports binding beans that are local for the template only + // in this local mode then we need to check for side-effects (see further) + LocalBeanRepositoryAware localBeans = null; + if (getCamelContextReference().getRegistry() instanceof LocalBeanRepositoryAware) { + localBeans = (LocalBeanRepositoryAware) getCamelContextReference().getRegistry(); + } try { RouteDefinitionHelper.forceAssignIds(getCamelContextReference(), routeDefinitions); for (RouteDefinition routeDefinition : routeDefinitions) { // assign ids to the routes and validate that the id's is all unique String duplicate = RouteDefinitionHelper.validateUniqueIds(routeDefinition, routeDefinitions); if (duplicate != null) { - throw new FailedToStartRouteException(routeDefinition.getId(), + throw new FailedToStartRouteException( + routeDefinition.getId(), "duplicate id detected: " + duplicate + ". Please correct ids to be unique among all your routes."); } // if the route definition was created via a route template then we need to prepare its parameters when the route is being created and started if (routeDefinition.isTemplate() != null && routeDefinition.isTemplate() && routeDefinition.getTemplateParameters() != null) { + + // apply configurer if any present + if (routeDefinition.getRouteTemplateContext().getConfigurer() != null) { + routeDefinition.getRouteTemplateContext().getConfigurer() + .accept(routeDefinition.getRouteTemplateContext()); + } + + // copy parameters/bean repository to not cause side-effect + Map<String, Object> params = new HashMap<>(routeDefinition.getTemplateParameters()); + LocalBeanRegistry bbr = (LocalBeanRegistry) routeDefinition.getRouteTemplateContext() + .getLocalBeanRepository(); + LocalBeanRegistry bbrCopy = new LocalBeanRegistry(); + + // make all bean in the bean repository use unique keys (need to add uuid counter) + // so when the route template is used again to create another route, then there is + // no side-effect from previously used values that Camel may use in its endpoint + // registry and elsewhere + if (bbr != null && !bbr.isEmpty()) { + for (Map.Entry<String, Object> param : params.entrySet()) { + Object value = param.getValue(); + if (value instanceof String) { + String oldKey = (String) value; + boolean clash = bbr.keys().stream().anyMatch(k -> k.equals(oldKey)); + if (clash) { + String newKey = oldKey + "-" + UUID.generateUuid(); + LOG.debug( + "Route: {} re-assigning local-bean id: {} to: {} to ensure ids are globally unique", + routeDefinition.getId(), oldKey, newKey); + bbrCopy.put(newKey, bbr.remove(oldKey)); + param.setValue(newKey); + } + } + } + // the remainder of the local beans must also have their ids made global unique + for (String oldKey : bbr.keySet()) { + String newKey = oldKey + "-" + UUID.generateUuid(); + LOG.debug( + "Route: {} re-assigning local-bean id: {} to: {} to ensure ids are globally unique", + routeDefinition.getId(), oldKey, newKey); + bbrCopy.put(newKey, bbr.get(oldKey)); + if (!params.containsKey(oldKey)) { + // if a bean was bound as local bean with a key and it was not defined as template parameter + // then store it as if it was a template parameter with same key=value which allows us + // to use this local bean in the route without any problem such as: + // to("bean:{{myBean}}") + // and myBean is the local bean id. + params.put(oldKey, newKey); + } + } + } + Properties prop = new Properties(); - prop.putAll(routeDefinition.getTemplateParameters()); + prop.putAll(params); pc.setLocalProperties(prop); + + // we need to shadow the bean registry on the CamelContext with the local beans from the route template context + if (localBeans != null && bbrCopy != null) { + localBeans.setLocalBeanRepository(bbrCopy); + } + + // need to reset auto assigned ids, so there is no clash when creating routes + ProcessorDefinitionHelper.resetAllAutoAssignedNodeIds(routeDefinition); } // must ensure route is prepared, before we can start it @@ -967,14 +1048,29 @@ public class FastCamelContext extends AbstractCamelContext implements CatalogCam routeDefinition.markPrepared(); } - Route route = new RouteReifier(getCamelContextReference(), routeDefinition).createRoute(); + StartupStepRecorder recorder = getCamelContextReference().adapt(ExtendedCamelContext.class) + .getStartupStepRecorder(); + StartupStep step = recorder.beginStep(Route.class, routeDefinition.getRouteId(), "Create Route"); + Route route = model.getModelReifierFactory().createRoute(this, routeDefinition); + recorder.endStep(step); + RouteService routeService = new RouteService(route); startRouteService(routeService, true); + + // clear local after the route is created via the reifier + pc.setLocalProperties(null); + if (localBeans != null) { + localBeans.setLocalBeanRepository(null); + } } } finally { if (!alreadyStartingRoutes) { setStartingRoutes(false); } + pc.setLocalProperties(null); + if (localBeans != null) { + localBeans.setLocalBeanRepository(null); + } } } diff --git a/integration-tests/kamelet/pom.xml b/integration-tests/kamelet/pom.xml index ad4d6b2..ade4967 100644 --- a/integration-tests/kamelet/pom.xml +++ b/integration-tests/kamelet/pom.xml @@ -56,6 +56,10 @@ <artifactId>camel-quarkus-timer</artifactId> </dependency> <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-bean</artifactId> + </dependency> + <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-resteasy</artifactId> </dependency> diff --git a/integration-tests/kamelet/src/main/java/org/apache/camel/quarkus/component/kamelet/it/KameletResource.java b/integration-tests/kamelet/src/main/java/org/apache/camel/quarkus/component/kamelet/it/KameletResource.java index 9484755..bf61c5b 100644 --- a/integration-tests/kamelet/src/main/java/org/apache/camel/quarkus/component/kamelet/it/KameletResource.java +++ b/integration-tests/kamelet/src/main/java/org/apache/camel/quarkus/component/kamelet/it/KameletResource.java @@ -21,6 +21,7 @@ import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; +import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; @@ -64,4 +65,11 @@ public class KameletResource { public String kameletChain(String message) throws Exception { return fluentProducerTemplate.to("direct:chain").withBody(message).request(String.class); } + + @Path("/invoke/{name}") + @POST + @Produces(MediaType.TEXT_PLAIN) + public String invoke(@PathParam("name") String name, String message) throws Exception { + return fluentProducerTemplate.toF("kamelet:%s", name).withBody(message).request(String.class); + } } diff --git a/integration-tests/kamelet/src/main/java/org/apache/camel/quarkus/component/kamelet/it/KameletRoutes.java b/integration-tests/kamelet/src/main/java/org/apache/camel/quarkus/component/kamelet/it/KameletRoutes.java index 84be64c..7062b0a 100644 --- a/integration-tests/kamelet/src/main/java/org/apache/camel/quarkus/component/kamelet/it/KameletRoutes.java +++ b/integration-tests/kamelet/src/main/java/org/apache/camel/quarkus/component/kamelet/it/KameletRoutes.java @@ -16,7 +16,11 @@ */ package org.apache.camel.quarkus.component.kamelet.it; +import java.util.Locale; + +import io.quarkus.runtime.annotations.RegisterForReflection; import org.apache.camel.Exchange; +import org.apache.camel.Processor; import org.apache.camel.builder.RouteBuilder; public class KameletRoutes extends RouteBuilder { @@ -44,8 +48,27 @@ public class KameletRoutes extends RouteBuilder { .from("kamelet:source") .setBody().simple("{{prefix}} ${body} {{suffix}}"); + routeTemplate("toUpperWithBean") + .templateBean("to-upper", new ToUpperProcessor()) + .from("kamelet:source") + .to("bean:{{to-upper}}"); + + routeTemplate("toUpperWithClass") + .templateBean("to-upper", ToUpperProcessor.class) + .from("kamelet:source") + .to("bean:{{to-upper}}"); + from("direct:chain") .to("kamelet:echo/1?prefix=Camel Quarkus&suffix=Chained") .to("kamelet:echo/2?prefix=Hello&suffix=Route"); } + + @RegisterForReflection + public static class ToUpperProcessor implements Processor { + @Override + public void process(Exchange exchange) throws Exception { + exchange.getMessage().setBody( + exchange.getMessage().getBody(String.class).toUpperCase(Locale.US)); + } + } } diff --git a/integration-tests/kamelet/src/test/java/org/apache/camel/quarkus/component/kamelet/it/KameletTest.java b/integration-tests/kamelet/src/test/java/org/apache/camel/quarkus/component/kamelet/it/KameletTest.java index 50f494d..77a6607 100644 --- a/integration-tests/kamelet/src/test/java/org/apache/camel/quarkus/component/kamelet/it/KameletTest.java +++ b/integration-tests/kamelet/src/test/java/org/apache/camel/quarkus/component/kamelet/it/KameletTest.java @@ -65,4 +65,23 @@ class KameletTest { .statusCode(200) .body(is("Hello Camel Quarkus Kamelet Chained Route")); } + + @Test + public void testInvoke() { + RestAssured.given() + .contentType(ContentType.TEXT) + .body("Kamelet") + .post("/kamelet/invoke/toUpperWithBean") + .then() + .statusCode(200) + .body(is("KAMELET")); + + RestAssured.given() + .contentType(ContentType.TEXT) + .body("Kamelet2") + .post("/kamelet/invoke/toUpperWithClass") + .then() + .statusCode(200) + .body(is("KAMELET2")); + } }
