This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch feature/CAMEL-23680-group-variable-scope in repository https://gitbox.apache.org/repos/asf/camel.git
commit ac96324e6e987314e65ee0c37273b1582bc103f0 Author: Claus Ibsen <[email protected]> AuthorDate: Sun Jun 7 09:15:59 2026 +0200 CAMEL-23680: Add group as scope to variables Co-Authored-By: Claude <[email protected]> Signed-off-by: Claus Ibsen <[email protected]> --- .../camel/spi/VariableRepositoryFactory.java | 7 + .../engine/DefaultVariableRepositoryFactory.java | 20 ++ .../camel/processor/SetGroupVariableTest.java | 126 ++++++++++++ .../camel/support/GroupVariableRepositoryTest.java | 194 +++++++++++++++++++ .../camel/main/MainSupportModelConfigurer.java | 4 + .../camel/support/GroupVariableRepository.java | 215 +++++++++++++++++++++ docs/user-manual/modules/ROOT/pages/variables.adoc | 38 +++- 7 files changed, 600 insertions(+), 4 deletions(-) diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/VariableRepositoryFactory.java b/core/camel-api/src/main/java/org/apache/camel/spi/VariableRepositoryFactory.java index 749f56adcfd3..4a190295edc2 100644 --- a/core/camel-api/src/main/java/org/apache/camel/spi/VariableRepositoryFactory.java +++ b/core/camel-api/src/main/java/org/apache/camel/spi/VariableRepositoryFactory.java @@ -35,6 +35,13 @@ public interface VariableRepositoryFactory { */ String ROUTE_VARIABLE_REPOSITORY_ID = "route-variable-repository"; + /** + * Registry bean id for group {@link VariableRepository}. + * + * @since 4.21 + */ + String GROUP_VARIABLE_REPOSITORY_ID = "group-variable-repository"; + /** * Gets the {@link VariableRepository} for the given id * diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultVariableRepositoryFactory.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultVariableRepositoryFactory.java index 8d834c145edb..d130c8c282b5 100644 --- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultVariableRepositoryFactory.java +++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultVariableRepositoryFactory.java @@ -27,6 +27,7 @@ import org.apache.camel.spi.VariableRepository; import org.apache.camel.spi.VariableRepositoryFactory; import org.apache.camel.support.CamelContextHelper; import org.apache.camel.support.GlobalVariableRepository; +import org.apache.camel.support.GroupVariableRepository; import org.apache.camel.support.LifecycleStrategySupport; import org.apache.camel.support.RouteVariableRepository; import org.apache.camel.support.service.ServiceSupport; @@ -45,6 +46,7 @@ public class DefaultVariableRepositoryFactory extends ServiceSupport implements private final CamelContext camelContext; private VariableRepository global; private VariableRepository route; + private VariableRepository group; private FactoryFinder factoryFinder; public DefaultVariableRepositoryFactory(CamelContext camelContext) { @@ -64,6 +66,9 @@ public class DefaultVariableRepositoryFactory extends ServiceSupport implements if (route != null && "route".equals(id)) { return route; } + if (group != null && "group".equals(id)) { + return group; + } VariableRepository repo = CamelContextHelper.lookup(camelContext, id, VariableRepository.class); if (repo == null) { @@ -119,6 +124,18 @@ public class DefaultVariableRepositoryFactory extends ServiceSupport implements camelContext.getRegistry().bind(ROUTE_VARIABLE_REPOSITORY_ID, route); } + // let's see if there is a custom group repo + repo = getVariableRepository("group"); + if (repo != null) { + if (!(repo instanceof GroupVariableRepository)) { + LOG.info("Using VariableRepository: {} as group repository", repo.getId()); + } + group = repo; + } else { + group = new GroupVariableRepository(); + camelContext.getRegistry().bind(GROUP_VARIABLE_REPOSITORY_ID, group); + } + if (!camelContext.hasService(global)) { camelContext.addService(global); } @@ -134,6 +151,9 @@ public class DefaultVariableRepositoryFactory extends ServiceSupport implements } }); } + if (!camelContext.hasService(group)) { + camelContext.addService(group); + } } } diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/SetGroupVariableTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/SetGroupVariableTest.java new file mode 100644 index 000000000000..fe7ce711b973 --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/processor/SetGroupVariableTest.java @@ -0,0 +1,126 @@ +/* + * 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.processor; + +import java.util.List; + +import org.apache.camel.ContextTestSupport; +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class SetGroupVariableTest extends ContextTestSupport { + + private MockEndpoint end; + + @Test + public void testSetGroupVariable() throws Exception { + assertNull(context.getVariable("group:teamA:foo")); + assertNull(context.getVariable("group:teamB:foo")); + + end.expectedMessageCount(2); + + template.sendBody("direct:teamA", "<blah/>"); + template.sendBody("direct:teamB", "<blah/>"); + + assertMockEndpointsSatisfied(); + + // variables should be stored on exchange, not accessible from exchange directly + List<Exchange> exchanges = end.getExchanges(); + Exchange exchange = exchanges.get(0); + assertNull(exchange.getVariable("foo")); + + // should be stored as group variables + assertEquals("bar", context.getVariable("group:teamA:foo")); + assertEquals("baz", context.getVariable("group:teamB:foo")); + } + + @Test + public void testGroupVariableIsolation() throws Exception { + end.expectedMessageCount(1); + + template.sendBody("direct:teamA", "<blah/>"); + + assertMockEndpointsSatisfied(); + + // teamA has the variable, teamB does not + assertEquals("bar", context.getVariable("group:teamA:foo")); + assertNull(context.getVariable("group:teamB:foo")); + } + + @Test + public void testGroupVariableSimpleLanguage() throws Exception { + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedBodiesReceived("Value is bar"); + + template.sendBody("direct:simple", "<blah/>"); + + assertMockEndpointsSatisfied(); + } + + @Test + public void testCrossRouteGroupVariable() throws Exception { + MockEndpoint mock = getMockEndpoint("mock:cross"); + mock.expectedBodiesReceived("shared-value"); + + // route "setter" sets the group variable, route "reader" reads it + template.sendBody("direct:setter", "<blah/>"); + template.sendBody("direct:reader", "<blah/>"); + + assertMockEndpointsSatisfied(); + } + + @Override + @BeforeEach + public void setUp() throws Exception { + super.setUp(); + end = getMockEndpoint("mock:end"); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:teamA").routeId("routeA") + .setVariable("group:teamA:foo").constant("bar") + .to("mock:end"); + + from("direct:teamB").routeId("routeB") + .setVariable("group:teamB:foo").constant("baz") + .to("mock:end"); + + from("direct:simple").routeId("routeSimple") + .setVariable("group:teamA:foo").constant("bar") + .transform().simple("Value is ${variable.group:teamA:foo}") + .to("mock:result"); + + from("direct:setter").routeId("routeSetter") + .setVariable("group:shared:myKey").constant("shared-value") + .to("mock:end"); + + from("direct:reader").routeId("routeReader") + .setBody().variable("group:shared:myKey") + .to("mock:cross"); + } + }; + } +} diff --git a/core/camel-core/src/test/java/org/apache/camel/support/GroupVariableRepositoryTest.java b/core/camel-core/src/test/java/org/apache/camel/support/GroupVariableRepositoryTest.java new file mode 100644 index 000000000000..435acaece322 --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/support/GroupVariableRepositoryTest.java @@ -0,0 +1,194 @@ +/* + * 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 java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class GroupVariableRepositoryTest { + + private GroupVariableRepository repo; + + @BeforeEach + public void setUp() { + repo = new GroupVariableRepository(); + } + + @Test + public void testGetId() { + assertEquals("group", repo.getId()); + } + + @Test + public void testSetAndGetVariable() { + repo.setVariable("teamA:foo", "bar"); + assertEquals("bar", repo.getVariable("teamA:foo")); + } + + @Test + public void testVariableIsolationBetweenGroups() { + repo.setVariable("teamA:key", "valueA"); + repo.setVariable("teamB:key", "valueB"); + + assertEquals("valueA", repo.getVariable("teamA:key")); + assertEquals("valueB", repo.getVariable("teamB:key")); + } + + @Test + public void testMultipleVariablesInSameGroup() { + repo.setVariable("teamA:foo", "1"); + repo.setVariable("teamA:bar", "2"); + repo.setVariable("teamA:baz", "3"); + + assertEquals("1", repo.getVariable("teamA:foo")); + assertEquals("2", repo.getVariable("teamA:bar")); + assertEquals("3", repo.getVariable("teamA:baz")); + assertEquals(3, repo.size()); + } + + @Test + public void testGetNonExistentVariable() { + assertNull(repo.getVariable("teamA:missing")); + } + + @Test + public void testGetNonExistentGroup() { + assertNull(repo.getVariable("noSuchGroup:key")); + } + + @Test + public void testRemoveVariable() { + repo.setVariable("teamA:foo", "bar"); + Object removed = repo.removeVariable("teamA:foo"); + + assertEquals("bar", removed); + assertNull(repo.getVariable("teamA:foo")); + } + + @Test + public void testRemoveWildcard() { + repo.setVariable("teamA:foo", "1"); + repo.setVariable("teamA:bar", "2"); + repo.setVariable("teamB:baz", "3"); + + repo.removeVariable("teamA:*"); + + assertNull(repo.getVariable("teamA:foo")); + assertNull(repo.getVariable("teamA:bar")); + assertEquals("3", repo.getVariable("teamB:baz")); + assertEquals(1, repo.size()); + } + + @Test + public void testSetNullRemoves() { + repo.setVariable("teamA:foo", "bar"); + repo.setVariable("teamA:foo", null); + + assertNull(repo.getVariable("teamA:foo")); + } + + @Test + public void testGetGroupIds() { + repo.setVariable("teamA:foo", "1"); + repo.setVariable("teamB:bar", "2"); + repo.setVariable("teamC:baz", "3"); + + Set<String> ids = repo.getGroupIds(); + assertEquals(Set.of("teamA", "teamB", "teamC"), ids); + } + + @Test + public void testGetGroupIdsEmpty() { + assertTrue(repo.getGroupIds().isEmpty()); + } + + @Test + public void testGetGroupIdsAfterRemoveWildcard() { + repo.setVariable("teamA:foo", "1"); + repo.setVariable("teamB:bar", "2"); + + repo.removeVariable("teamA:*"); + + assertEquals(Set.of("teamB"), repo.getGroupIds()); + } + + @Test + public void testNames() { + repo.setVariable("teamA:foo", "1"); + repo.setVariable("teamB:bar", "2"); + + Set<String> names = repo.names().collect(Collectors.toSet()); + assertEquals(Set.of("teamA:foo", "teamB:bar"), names); + } + + @Test + public void testGetVariables() { + repo.setVariable("teamA:foo", "1"); + repo.setVariable("teamB:bar", "2"); + + Map<String, Object> vars = repo.getVariables(); + assertEquals(2, vars.size()); + assertEquals("1", vars.get("teamA:foo")); + assertEquals("2", vars.get("teamB:bar")); + } + + @Test + public void testHasVariables() { + assertFalse(repo.hasVariables()); + + repo.setVariable("teamA:foo", "bar"); + assertTrue(repo.hasVariables()); + } + + @Test + public void testSize() { + assertEquals(0, repo.size()); + + repo.setVariable("teamA:foo", "1"); + repo.setVariable("teamA:bar", "2"); + repo.setVariable("teamB:baz", "3"); + assertEquals(3, repo.size()); + } + + @Test + public void testClear() { + repo.setVariable("teamA:foo", "1"); + repo.setVariable("teamB:bar", "2"); + + repo.clear(); + + assertFalse(repo.hasVariables()); + assertEquals(0, repo.size()); + } + + @Test + public void testMissingColonThrows() { + assertThrows(IllegalArgumentException.class, () -> repo.getVariable("noColon")); + assertThrows(IllegalArgumentException.class, () -> repo.setVariable("noColon", "value")); + assertThrows(IllegalArgumentException.class, () -> repo.removeVariable("noColon")); + } +} diff --git a/core/camel-main/src/main/java/org/apache/camel/main/MainSupportModelConfigurer.java b/core/camel-main/src/main/java/org/apache/camel/main/MainSupportModelConfigurer.java index 117d75e87b6d..935f7347617a 100644 --- a/core/camel-main/src/main/java/org/apache/camel/main/MainSupportModelConfigurer.java +++ b/core/camel-main/src/main/java/org/apache/camel/main/MainSupportModelConfigurer.java @@ -101,6 +101,10 @@ public final class MainSupportModelConfigurer { id = "route"; key = key.substring(6); key = StringHelper.replaceFirst(key, ".", ":"); + } else if (key.startsWith("group.")) { + id = "group"; + key = key.substring(6); + key = StringHelper.replaceFirst(key, ".", ":"); } else if (key.startsWith("global.")) { id = "global"; key = key.substring(7); diff --git a/core/camel-support/src/main/java/org/apache/camel/support/GroupVariableRepository.java b/core/camel-support/src/main/java/org/apache/camel/support/GroupVariableRepository.java new file mode 100644 index 000000000000..a9f9e33d94ee --- /dev/null +++ b/core/camel-support/src/main/java/org/apache/camel/support/GroupVariableRepository.java @@ -0,0 +1,215 @@ +/* + * 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 java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Stream; + +import org.apache.camel.CamelContext; +import org.apache.camel.CamelContextAware; +import org.apache.camel.StreamCache; +import org.apache.camel.StreamCacheException; +import org.apache.camel.spi.BrowsableVariableRepository; +import org.apache.camel.spi.StreamCachingStrategy; +import org.apache.camel.spi.VariableRepository; +import org.apache.camel.support.service.ServiceSupport; +import org.apache.camel.util.StringHelper; + +/** + * Group {@link VariableRepository} which stores variables in-memory per named group. + * <p> + * Variables are scoped by group name using the syntax {@code groupId:variableName}. This allows sharing variables + * across a subset of routes — wider than per-route but narrower than global scope. + * + * @since 4.21 + */ +public final class GroupVariableRepository extends ServiceSupport implements BrowsableVariableRepository, CamelContextAware { + + private final Map<String, Map<String, Object>> groups = new ConcurrentHashMap<>(); + private CamelContext camelContext; + private StreamCachingStrategy strategy; + + @Override + public CamelContext getCamelContext() { + return camelContext; + } + + @Override + public void setCamelContext(CamelContext camelContext) { + this.camelContext = camelContext; + } + + @Override + public Object getVariable(String name) { + String id = StringHelper.before(name, ":"); + String key = StringHelper.after(name, ":"); + if (id == null || key == null) { + throw new IllegalArgumentException("Name must be groupId:name syntax"); + } + Object answer = null; + Map<String, Object> variables = groups.get(id); + if (variables != null) { + answer = variables.get(key); + } + if (answer instanceof StreamCache sc) { + // reset so the cache is ready to be used as a variable + sc.reset(); + } + return answer; + } + + @Override + public void setVariable(String name, Object value) { + String id = StringHelper.before(name, ":"); + String key = StringHelper.after(name, ":"); + if (id == null || key == null) { + throw new IllegalArgumentException("Name must be groupId:name syntax"); + } + + if (value != null && strategy != null) { + StreamCache sc = convertToStreamCache(value); + if (sc != null) { + value = sc; + } + } + if (value != null) { + Map<String, Object> variables = groups.computeIfAbsent(id, s -> new ConcurrentHashMap<>(8)); + // avoid the NullPointException + variables.put(key, value); + } else { + // if the value is null, we just remove the key from the map + Map<String, Object> variables = groups.get(id); + if (variables != null) { + variables.remove(key); + } + } + } + + public boolean hasVariables() { + for (var vars : groups.values()) { + if (!vars.isEmpty()) { + return true; + } + } + return false; + } + + public int size() { + int size = 0; + for (var vars : groups.values()) { + size += vars.size(); + } + return size; + } + + public Stream<String> names() { + List<String> answer = new ArrayList<>(); + for (Map.Entry<String, Map<String, Object>> entry : groups.entrySet()) { + String id = entry.getKey(); + Map<String, Object> values = entry.getValue(); + for (var e : values.entrySet()) { + answer.add(id + ":" + e.getKey()); + } + } + return answer.stream(); + } + + public Map<String, Object> getVariables() { + Map<String, Object> answer = new ConcurrentHashMap<>(); + for (Map.Entry<String, Map<String, Object>> entry : groups.entrySet()) { + String id = entry.getKey(); + Map<String, Object> values = entry.getValue(); + for (var e : values.entrySet()) { + answer.put(id + ":" + e.getKey(), e.getValue()); + } + } + return answer; + } + + /** + * Gets the ids of all groups that currently have variables. + */ + public Set<String> getGroupIds() { + return Collections.unmodifiableSet(groups.keySet()); + } + + public void clear() { + groups.clear(); + } + + @Override + public String getId() { + return "group"; + } + + @Override + public Object removeVariable(String name) { + String id = StringHelper.before(name, ":"); + String key = StringHelper.after(name, ":"); + if (id == null || key == null) { + throw new IllegalArgumentException("Name must be groupId:name syntax"); + } + + Map<String, Object> variables = groups.get(id); + if (variables != null) { + if ("*".equals(key)) { + variables.clear(); + groups.remove(id); + return null; + } else { + return variables.remove(key); + } + } + return null; + } + + @Override + protected void doInit() throws Exception { + super.doInit(); + + if (camelContext != null && camelContext.isStreamCaching()) { + strategy = camelContext.getStreamCachingStrategy(); + } + } + + private StreamCache convertToStreamCache(Object body) { + // check if body is already cached + if (body == null) { + return null; + } else if (body instanceof StreamCache sc) { + // reset so the cache is ready to be used before processing + sc.reset(); + return sc; + } + return tryStreamCache(body); + } + + private StreamCache tryStreamCache(Object body) { + try { + // cache the body and if we could do that replace it as the new body + return strategy.cache(body); + } catch (Exception e) { + throw new StreamCacheException(body, e); + } + } + +} diff --git a/docs/user-manual/modules/ROOT/pages/variables.adoc b/docs/user-manual/modules/ROOT/pages/variables.adoc index 239019c0e855..8130a485d5ff 100644 --- a/docs/user-manual/modules/ROOT/pages/variables.adoc +++ b/docs/user-manual/modules/ROOT/pages/variables.adoc @@ -5,7 +5,7 @@ In Camel 4.4, we have introduced the concept of _variables_. A variable is a key/value that can hold a value that can either be private per `Exchange`, -or shared per route, or per `CamelContext`. +or shared per route, per named group, or per `CamelContext`. IMPORTANT: You can also use _exchange properties_ as variables, but the exchange properties are also used internally by Camel, and some EIPs and components. With the newly introduced _variables_ then these are exclusively for end users. @@ -16,6 +16,7 @@ The variables are stored in one or more `org.apache.camel.spi.VariableRepository - `ExchangeVariableRepository` - A private repository per `Exchange` that holds variables that are private for the lifecycle of each `Exchange`. - `RouteVariableRepository` - Uses `route` as id. A single repository, that holds variables per `Route`. +- `GroupVariableRepository` - Uses `group` as id. A single repository, that holds variables per named group. This allows sharing variables across a subset of routes — wider than per-route but narrower than global scope. - `GlobalVariableRepository` - Uses `global` as id. A single global repository for the entire `CamelContext`. The `ExchangeVariableRepository` is special as its private per exchange and is the default repository when used during routing. @@ -30,9 +31,9 @@ from management tooling, CLI, and the developer console. You can implement custom `org.apache.camel.spi.VariableRepository` and plugin to be used out of the box with Apache Camel. For example, you can build a custom repository that stores the variables in a database, so they are persisted. -Each repository must have its own unique id. However, it's also possible to replace the default `global`, or `route` repositories with another. +Each repository must have its own unique id. However, it's also possible to replace the default `global`, `route`, or `group` repositories with another. -IMPORTANT: The id `exchange` and `header` is reserved by Camel internally and should not be used as id for custom repositories. +IMPORTANT: The id `exchange`, `header`, `global`, `route`, and `group` are reserved by Camel internally and should not be used as id for custom repositories. == Getting and setting variables from Java API @@ -93,6 +94,26 @@ Object val = context.getVariable("route:myRouteId:myRouteKey"); String str = context.getVariable("route:myRouteId:myRouteKey", String.class); ---- +You can assign a variable to a named group with `group:` as follows: + +[source,java] +---- +exchange.setVariable("group:teamA:myKey", someObjectHere); +---- + +And you can get group variables as well: + +[source,java] +---- +Object val = exchange.getVariable("group:teamA:myKey"); + +// you can get the value as a specific type +String str = exchange.getVariable("group:teamA:myKey", String.class); +---- + +Group variables are shared across all routes that use the same group name, +which makes them useful for sharing state between a subset of related routes. + == Setting and getting variables from DSL It is also possible to use variables in Camel xref:routes.adoc[routes] using the: @@ -233,7 +254,7 @@ YAML:: == Configuring initial variables on startup -When Camel is starting then it's possible to configure initial variables for `global` and `route` repositories only. +When Camel is starting then it's possible to configure initial variables for `global`, `route`, and `group` repositories only. This can be done in `application.properties` as shown below: @@ -256,6 +277,15 @@ camel.variable.random = 999 Here the gold variable is set on the `route` repository, and the other variables are set on the `global` repository. +You can also set group scoped variables, using `group.` as prefix. The dot is used to separate +the group id from the variable name, eg `teamA.threshold`. + +[source,properties] +---- +camel.variable.group.teamA.threshold = 100 +camel.variable.group.teamB.region = EU +---- + The value of a variable can also be loaded from the file system, such as a JSon file. To do this, you should prefix the value with `resource:file:` or `resource:classpath:` to load from the file system or classpath, as shown below:
