diff --git a/integration-test-groups/foundation/pom.xml b/integration-test-groups/foundation/pom.xml
index 8b02d4da324a..0e476ef088db 100644
--- a/integration-test-groups/foundation/pom.xml
+++ b/integration-test-groups/foundation/pom.xml
@@ -57,6 +57,7 @@
timer
transformer
type-converter
+ variables
diff --git a/integration-test-groups/foundation/variables/pom.xml b/integration-test-groups/foundation/variables/pom.xml
new file mode 100644
index 000000000000..f466f4944cfa
--- /dev/null
+++ b/integration-test-groups/foundation/variables/pom.xml
@@ -0,0 +1,149 @@
+
+
+
+ 4.0.0
+
+ org.apache.camel.quarkus
+ camel-quarkus-build-parent-it
+ 3.7.0-SNAPSHOT
+ ../../../poms/build-parent-it/pom.xml
+
+
+ camel-quarkus-integration-test-variables
+ Camel Quarkus :: Integration Tests :: Variables
+
+
+
+ org.apache.camel.quarkus
+ camel-quarkus-bean
+
+
+ org.apache.camel.quarkus
+ camel-quarkus-mock
+
+
+ org.apache.camel.quarkus
+ camel-quarkus-direct
+
+
+ io.quarkus
+ quarkus-resteasy
+
+
+
+
+
+ io.quarkus
+ quarkus-junit5
+ test
+
+
+ io.rest-assured
+ rest-assured
+ test
+
+
+ org.apache.camel.quarkus
+ camel-quarkus-integration-wiremock-support
+ test
+
+
+
+
+
+ native
+
+
+ native
+
+
+
+ native
+
+
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+
+
+
+ integration-test
+ verify
+
+
+
+
+
+
+
+
+ virtualDependencies
+
+
+ !noVirtualDependencies
+
+
+
+
+
+ org.apache.camel.quarkus
+ camel-quarkus-bean-deployment
+ ${project.version}
+ pom
+ test
+
+
+ *
+ *
+
+
+
+
+ org.apache.camel.quarkus
+ camel-quarkus-direct-deployment
+ ${project.version}
+ pom
+ test
+
+
+ *
+ *
+
+
+
+
+ org.apache.camel.quarkus
+ camel-quarkus-mock-deployment
+ ${project.version}
+ pom
+ test
+
+
+ *
+ *
+
+
+
+
+
+
+
+
diff --git a/integration-test-groups/foundation/variables/src/main/java/org/apache/camel/quarkus/variables/it/VariablesProducers.java b/integration-test-groups/foundation/variables/src/main/java/org/apache/camel/quarkus/variables/it/VariablesProducers.java
new file mode 100644
index 000000000000..c51d6607a2ff
--- /dev/null
+++ b/integration-test-groups/foundation/variables/src/main/java/org/apache/camel/quarkus/variables/it/VariablesProducers.java
@@ -0,0 +1,71 @@
+/*
+ * 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.quarkus.variables.it;
+
+import io.quarkus.runtime.annotations.RegisterForReflection;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.enterprise.inject.Alternative;
+import jakarta.inject.Named;
+import org.apache.camel.Variable;
+import org.apache.camel.spi.VariableRepository;
+import org.apache.camel.support.service.ServiceSupport;
+
+public class VariablesProducers {
+
+ //repository is created as alternative to be disabled by default
+ //QuarkusTestProfile is used to enable the bean for the appropriate tests.
+ @Named("global-variable-repository")
+ @Alternative
+ @ApplicationScoped
+ public static class MyGlobalRepo extends ServiceSupport implements VariableRepository {
+
+ private Object value;
+
+ @Override
+ public String getId() {
+ return "myGlobal";
+ }
+
+ @Override
+ public Object getVariable(String name) {
+ if (value != null) {
+ return "!" + value + "!";
+ }
+ return null;
+ }
+
+ @Override
+ public void setVariable(String name, Object value) {
+ this.value = value;
+ }
+
+ @Override
+ public Object removeVariable(String name) {
+ return null;
+ }
+ }
+
+ @Named("my-bean")
+ @ApplicationScoped
+ @RegisterForReflection(methods = true)
+ public static class MyBean {
+ public boolean matches(@Variable("location") String location) {
+ return "Medford".equals(location);
+ }
+ }
+
+}
diff --git a/integration-test-groups/foundation/variables/src/main/java/org/apache/camel/quarkus/variables/it/VariablesResource.java b/integration-test-groups/foundation/variables/src/main/java/org/apache/camel/quarkus/variables/it/VariablesResource.java
new file mode 100644
index 000000000000..57205f37ac69
--- /dev/null
+++ b/integration-test-groups/foundation/variables/src/main/java/org/apache/camel/quarkus/variables/it/VariablesResource.java
@@ -0,0 +1,186 @@
+/*
+ * 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.quarkus.variables.it;
+
+import java.util.List;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.core.Response;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.component.mock.MockEndpoint;
+
+@Path("/variables")
+@ApplicationScoped
+public class VariablesResource {
+
+ @Inject
+ ProducerTemplate producerTemplate;
+
+ @Inject
+ CamelContext context;
+
+ @Path("/setLocalVariable")
+ @POST
+ public String setLocalVariable(String body) throws Exception {
+ MockEndpoint end = context.getEndpoint("mock:setLocalVariableEnd", MockEndpoint.class);
+ end.expectedMessageCount(1);
+ end.expectedVariableReceived(VariablesRoutes.VARIABLE_NAME, VariablesRoutes.VARIABLE_VALUE);
+
+ producerTemplate.requestBody("direct:setLocalVariableStart", body, String.class);
+
+ // make sure we got the message
+ end.assertIsSatisfied();
+
+ // lets get the variable value
+ List exchanges = end.getExchanges();
+ Exchange exchange = exchanges.get(0);
+
+ return exchange.getVariable(VariablesRoutes.VARIABLE_NAME, String.class);
+ }
+
+ @Path("/setGlobalVariable")
+ @POST
+ public Response setGlobalVariable(String body) throws Exception {
+ if (context.getVariable(VariablesRoutes.VARIABLE_NAME) != null) {
+ return Response.status(500).entity(String.format("Variable '%s' has to be null before sending message to the rout.",
+ VariablesRoutes.VARIABLE_VALUE)).build();
+ }
+
+ MockEndpoint end = context.getEndpoint("mock:setGlobalVariableEnd", MockEndpoint.class);
+ end.expectedMessageCount(1);
+
+ producerTemplate.requestBody("direct:setGlobalVariableStart", body, String.class);
+
+ // make sure we got the message
+ end.assertIsSatisfied();
+
+ // lets get the variable value
+ List exchanges = end.getExchanges();
+ Exchange exchange = exchanges.get(0);
+
+ String resp = exchange.getVariable(VariablesRoutes.VARIABLE_NAME, String.class) + ","
+ + context.getVariable(VariablesRoutes.VARIABLE_NAME, String.class);
+ return Response.ok().entity(resp).build();
+ }
+
+ @Path("/removeLocalVariable")
+ @POST
+ public String removeLocalVariable(String body) throws Exception {
+ MockEndpoint end = context.getEndpoint("mock:removeLocalVariableEnd", MockEndpoint.class);
+ end.expectedMessageCount(1);
+
+ MockEndpoint mid = context.getEndpoint("mock:removeLocalVariableMid", MockEndpoint.class);
+ mid.expectedMessageCount(1);
+
+ producerTemplate.requestBody("direct:removeLocalVariableStart", body, String.class);
+
+ // make sure we got the message
+ end.assertIsSatisfied();
+ mid.assertIsSatisfied();
+
+ // lets get the variable value
+ List exchanges = end.getExchanges();
+ Exchange endExchange = exchanges.get(0);
+ exchanges = mid.getExchanges();
+ Exchange midExchange = exchanges.get(0);
+
+ return midExchange.getVariable(VariablesRoutes.VARIABLE_NAME, String.class) + ","
+ + endExchange.getVariable(VariablesRoutes.VARIABLE_NAME, String.class);
+ }
+
+ @Path("/removeGlobalVariable")
+ @POST
+ public String removeGlobalVariable(String body) throws Exception {
+ MockEndpoint mid = context.getEndpoint("mock:removeGlobalVariableMid", MockEndpoint.class);
+ mid.expectedMessageCount(1);
+
+ producerTemplate.requestBody("direct:removeGlobalVariableStart", body, String.class);
+
+ // make sure we got the message
+ mid.assertIsSatisfied();
+
+ // lets get the variable value
+ List exchanges = mid.getExchanges();
+ Exchange midExchange = exchanges.get(0);
+
+ return midExchange.getVariable(VariablesRoutes.VARIABLE_NAME, String.class) + ","
+ + context.getVariable(VariablesRoutes.VARIABLE_NAME, String.class);
+ }
+
+ @Path("/customGlobalRepository")
+ @POST
+ public Response customGlobalRepository(String body) throws Exception {
+ context.getRouteController().startRoute("customGlobalRepository");
+
+ MockEndpoint end = context.getEndpoint("mock:setGlobalCustomEnd", MockEndpoint.class);
+ end.expectedMessageCount(1);
+
+ producerTemplate.requestBody("direct:setGlobalCustomStart", body, String.class);
+
+ // make sure we got the message
+ end.assertIsSatisfied();
+
+ // lets get the variable value
+ List exchanges = end.getExchanges();
+ Exchange exchange = exchanges.get(0);
+
+ String resp = exchange.getVariable(VariablesRoutes.VARIABLE_NAME, String.class) + ","
+ + context.getVariable(VariablesRoutes.VARIABLE_NAME, String.class);
+ return Response.ok().entity(resp).build();
+ }
+
+ @Path("/convert")
+ @POST
+ public String convert(String body) throws Exception {
+ MockEndpoint end = context.getEndpoint("mock:convertEnd", MockEndpoint.class);
+ end.expectedMessageCount(1);
+
+ producerTemplate.requestBody("direct:convertStart", body, String.class);
+
+ // make sure we got the message
+ end.assertIsSatisfied();
+
+ List exchanges = end.getExchanges();
+ Exchange exchange = exchanges.get(0);
+
+ return exchange.getVariable(VariablesRoutes.VARIABLE_NAME, String.class);
+ }
+
+ @Path("/filter/{city}")
+ @POST
+ public Response filter(String body, @PathParam("city") String city) throws Exception {
+ MockEndpoint end = context.getEndpoint("mock:filterEnd", MockEndpoint.class);
+ end.expectedMessageCount(1);
+
+ producerTemplate.requestBodyAndHeader("direct:filterStart", body, "city", city, String.class);
+
+ try {
+ Exchange exhange = end.assertExchangeReceived(0);
+ return Response.ok().entity(exhange.getIn().getBody(String.class)).build();
+ } catch (AssertionError e) {
+ return Response.status(204).build();
+ }
+
+ }
+
+}
diff --git a/integration-test-groups/foundation/variables/src/main/java/org/apache/camel/quarkus/variables/it/VariablesRoutes.java b/integration-test-groups/foundation/variables/src/main/java/org/apache/camel/quarkus/variables/it/VariablesRoutes.java
new file mode 100644
index 000000000000..7bbc71643499
--- /dev/null
+++ b/integration-test-groups/foundation/variables/src/main/java/org/apache/camel/quarkus/variables/it/VariablesRoutes.java
@@ -0,0 +1,71 @@
+/*
+ * 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.quarkus.variables.it;
+
+import org.apache.camel.builder.RouteBuilder;
+
+public class VariablesRoutes extends RouteBuilder {
+
+ public static String VARIABLE_NAME = "foo";
+ public static String VARIABLE_VALUE = "bar";
+
+ @Override
+ public void configure() throws Exception {
+ transformer().withDefaults();
+
+ from("direct:setLocalVariableStart")
+ .setVariable(VARIABLE_NAME)
+ .constant(VARIABLE_VALUE)
+ .to("mock:setLocalVariableEnd");
+
+ from("direct:setGlobalVariableStart")
+ .setVariable("global:" + VARIABLE_NAME)
+ .constant(VARIABLE_VALUE)
+ .to("mock:setGlobalVariableEnd");
+
+ from("direct:removeLocalVariableStart")
+ .setVariable(VARIABLE_NAME)
+ .constant(VARIABLE_VALUE)
+ .to("mock:removeLocalVariableMid")
+ .removeVariable(VARIABLE_NAME)
+ .to("mock:removeLocalVariableEnd");
+
+ from("direct:removeGlobalVariableStart")
+ .setVariable("global:" + VARIABLE_NAME)
+ .constant(VARIABLE_VALUE)
+ .to("mock:removeGlobalVariableMid")
+ .removeVariable("global:" + VARIABLE_NAME);
+
+ from("direct:setGlobalCustomStart")
+ .id("customGlobalRepository")
+ .autoStartup(false)
+ .setVariable("global:" + VARIABLE_NAME)
+ .constant(VARIABLE_VALUE)
+ .to("mock:setGlobalCustomEnd");
+
+ from("direct:convertStart")
+ .setVariable(VARIABLE_NAME)
+ .constant(11)
+ .convertVariableTo(VARIABLE_NAME, Double.class)
+ .to("mock:convertEnd");
+
+ from("direct:filterStart")
+ .setVariable("location", header("city"))
+ .filter().method("my-bean", "matches")
+ .to("mock:filterEnd");
+ }
+}
diff --git a/integration-test-groups/foundation/variables/src/test/java/org/apache/camel/quarkus/variables/it/CustomRepositoryVariablesTest.java b/integration-test-groups/foundation/variables/src/test/java/org/apache/camel/quarkus/variables/it/CustomRepositoryVariablesTest.java
new file mode 100644
index 000000000000..f15cab374f27
--- /dev/null
+++ b/integration-test-groups/foundation/variables/src/test/java/org/apache/camel/quarkus/variables/it/CustomRepositoryVariablesTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.quarkus.variables.it;
+
+import java.util.Collections;
+import java.util.Set;
+
+import io.quarkus.test.junit.QuarkusTest;
+import io.quarkus.test.junit.QuarkusTestProfile;
+import io.quarkus.test.junit.TestProfile;
+import io.restassured.RestAssured;
+import io.restassured.http.ContentType;
+import org.hamcrest.Matchers;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test is executed in JVM mode only because the profile enabling customVariableRepository can not be enabled for
+ * this class in the native (and stay disabled for the other test class).
+ * I think that it is not necessary to create a module for this test only, because it uses code tested by other tests
+ * and
+ * there is no reason to believe, that it fails in native.
+ */
+@QuarkusTest
+@TestProfile(CustomRepositoryVariablesTest.Profile.class)
+class CustomRepositoryVariablesTest {
+
+ @Test
+ public void testCustomGlobalRepository() {
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .post("/variables/customGlobalRepository")
+ .then()
+ .statusCode(200)
+ .body(Matchers.is("null,!" + VariablesRoutes.VARIABLE_VALUE + "!"));
+ }
+
+ public static class Profile implements QuarkusTestProfile {
+
+ @Override
+ public Set> getEnabledAlternatives() {
+ return Collections.singleton(VariablesProducers.MyGlobalRepo.class);
+ }
+ }
+
+}
diff --git a/integration-test-groups/foundation/variables/src/test/java/org/apache/camel/quarkus/variables/it/VariablesIT.java b/integration-test-groups/foundation/variables/src/test/java/org/apache/camel/quarkus/variables/it/VariablesIT.java
new file mode 100644
index 000000000000..ee312a210974
--- /dev/null
+++ b/integration-test-groups/foundation/variables/src/test/java/org/apache/camel/quarkus/variables/it/VariablesIT.java
@@ -0,0 +1,24 @@
+/*
+ * 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.quarkus.variables.it;
+
+import io.quarkus.test.junit.QuarkusIntegrationTest;
+
+@QuarkusIntegrationTest
+class VariablesIT extends VariablesTest {
+
+}
diff --git a/integration-test-groups/foundation/variables/src/test/java/org/apache/camel/quarkus/variables/it/VariablesTest.java b/integration-test-groups/foundation/variables/src/test/java/org/apache/camel/quarkus/variables/it/VariablesTest.java
new file mode 100644
index 000000000000..10ad5c7b91fb
--- /dev/null
+++ b/integration-test-groups/foundation/variables/src/test/java/org/apache/camel/quarkus/variables/it/VariablesTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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.quarkus.variables.it;
+
+import io.quarkus.test.junit.QuarkusTest;
+import io.restassured.RestAssured;
+import io.restassured.http.ContentType;
+import org.hamcrest.Matchers;
+import org.junit.jupiter.api.Test;
+
+@QuarkusTest
+class VariablesTest {
+
+ @Test
+ public void testSetLocalVariable() {
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .post("/variables/setLocalVariable")
+ .then()
+ .statusCode(200)
+ .body(Matchers.is(VariablesRoutes.VARIABLE_VALUE));
+ }
+
+ @Test
+ public void testSetGlobalVariable() {
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .post("/variables/setGlobalVariable")
+ .then()
+ .statusCode(200)
+ .body(Matchers.is("null," + VariablesRoutes.VARIABLE_VALUE));
+ }
+
+ @Test
+ public void testRemoveLocalVariable() {
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .post("/variables/removeLocalVariable")
+ .then()
+ .statusCode(200)
+ .body(Matchers.is(VariablesRoutes.VARIABLE_VALUE + ",null"));
+ }
+
+ @Test
+ public void testRemoveGlobalVariable() {
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .post("/variables/removeGlobalVariable")
+ .then()
+ .statusCode(200)
+ .body(Matchers.is("null,null"));
+ }
+
+ @Test
+ public void testConvert() {
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body("aaaa")
+ .post("/variables/convert")
+ .then()
+ .statusCode(200)
+ .body(Matchers.is("11.0"));
+ }
+
+ @Test
+ public void testFilter() {
+ //first call fails, because city Gotham is filtered Out
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body("Sheldon")
+ .post("/variables/filter/Gotham")
+ .then()
+ .statusCode(204);
+
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body("Sheldon")
+ .post("/variables/filter/Medford")
+ .then()
+ .statusCode(200)
+ .body(Matchers.is("Sheldon"));
+ }
+}