This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 08b7b765432e CAMEL-25978: camel-controlbus - the language command is
off by default, with an option that lists the languages it may use (#29750)
08b7b765432e is described below
commit 08b7b765432e63363ce964142b9bfbd7f52fcb30
Author: Claus Ibsen <[email protected]>
AuthorDate: Fri Nov 13 08:24:24 2026 +0100
CAMEL-25978: camel-controlbus - the language command is off by default,
with an option that lists the languages it may use (#29750)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
.../camel/catalog/components/controlbus.json | 6 +-
.../camel/catalog/docs/controlbus-component.adoc | 26 +++++++-
.../controlbus/ControlBusComponentConfigurer.java | 6 ++
.../controlbus/ControlBusEndpointConfigurer.java | 6 ++
.../controlbus/ControlBusEndpointUriFactory.java | 3 +-
.../camel/component/controlbus/controlbus.json | 6 +-
.../src/main/docs/controlbus-component.adoc | 26 +++++++-
.../component/controlbus/ControlBusComponent.java | 40 ++++++++++-
.../component/controlbus/ControlBusEndpoint.java | 16 +++++
.../controlbus/ControlBusLanguageAllowedTest.java | 78 ++++++++++++++++++++++
.../ControlBusLanguageSimpleStartRouteTest.java | 10 ++-
.../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc | 12 ++++
.../dsl/ControlbusComponentBuilderFactory.java | 21 ++++++
.../dsl/ControlBusEndpointBuilderFactory.java | 19 ++++++
14 files changed, 264 insertions(+), 11 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/controlbus.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/controlbus.json
index 63dda925923f..2c0db8d547b4 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/controlbus.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/controlbus.json
@@ -25,7 +25,8 @@
},
"componentProperties": {
"lazyStartProducer": { "index": 0, "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 [...]
- "autowiredEnabled": { "index": 1, "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 t [...]
+ "autowiredEnabled": { "index": 1, "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 t [...]
+ "allowedLanguages": { "index": 2, "kind": "property", "displayName":
"Allowed Languages", "group": "security", "label": "security", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "description": "The names of the languages
the language command may use, separated by comma, such as simple. The language
command evaluates the message body as an expression, so it is off until the
language is in this list: a con [...]
},
"bodyTypes": {
"producerIn": { "carriers": [ "any" ], "byOption": [ { "option":
"command", "value": "language", "carriers": [ "text", "bytes", "stream", "file"
] } ], "description": "The route actions do not read the body. The language
command evaluates the body as its expression, as text" },
@@ -39,6 +40,7 @@
"loggingLevel": { "index": 4, "kind": "parameter", "displayName": "Logging
Level", "group": "producer", "label": "", "required": false, "type": "enum",
"javaType": "org.apache.camel.LoggingLevel", "enum": [ "TRACE", "DEBUG",
"INFO", "WARN", "ERROR", "OFF" ], "deprecated": false, "autowired": false,
"secret": false, "defaultValue": "INFO", "description": "Logging level used for
logging when task is done, or if any exceptions occurred during processing the
task." },
"restartDelay": { "index": 5, "kind": "parameter", "displayName": "Restart
Delay", "group": "producer", "label": "", "required": false, "type": "integer",
"javaType": "int", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": 1000, "description": "The delay in millis to use when
restarting a route." },
"routeId": { "index": 6, "kind": "parameter", "displayName": "Route Id",
"group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "description": "To specify a route by its id. The special
keyword current indicates the current route." },
- "lazyStartProducer": { "index": 7, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "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 produc [...]
+ "lazyStartProducer": { "index": 7, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "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 produc [...]
+ "allowedLanguages": { "index": 8, "kind": "parameter", "displayName":
"Allowed Languages", "group": "security", "label": "security", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "description": "The names of the languages
the language command may use, separated by comma, such as simple. The language
command evaluates the message body as an expression, so it is off until the
language is in this list: a co [...]
}
}
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/controlbus-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/controlbus-component.adoc
index 05f6af24b0ce..e691bba99b5e 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/controlbus-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/controlbus-component.adoc
@@ -180,7 +180,29 @@ String xml =
template.requestBody("controlbus:route?action=stats", null, String.
=== Using Simple language
You can use the xref:languages:simple-language.adoc[Simple] language with the
control bus.
-For example, to stop a specific route, you can send a message to the
`"controlbus:language:simple"` endpoint containing the following message:
+
+The `language` command evaluates the message body as an expression, so it is
off by default.
+To turn it on, list the languages it may use in the `allowedLanguages` option,
separated by comma.
+Set it on the component to apply to every endpoint:
+
+[source,properties]
+----
+camel.component.controlbus.allowed-languages = simple
+----
+
+Or set it on the endpoint itself, which takes precedence over the list of the
component:
+
+[source,text]
+----
+controlbus:language:simple?allowedLanguages=simple
+----
+
+A `controlbus:language` endpoint whose language is not listed fails when it is
created, with an error that names the `allowedLanguages` option.
+The `route` command does not need this option.
+
+IMPORTANT: The body is evaluated as an expression with the full power of the
language: only send it text that comes from the route, never the content of a
message from an untrusted sender.
+
+With `simple` allowed on the component, to stop a specific route, you can send
a message to the `"controlbus:language:simple"` endpoint containing the
following message:
._Java-only: Java test API (ProducerTemplate)_
[source,java]
@@ -216,5 +238,5 @@ message we sent to the control bus component.
[TIP]
====
-You can also use other languages such as
xref:languages:groovy-language.adoc[Groovy], etc.
+You can also use other languages such as
xref:languages:groovy-language.adoc[Groovy], etc., when they are listed in the
`allowedLanguages` option.
====
diff --git
a/components/camel-controlbus/src/generated/java/org/apache/camel/component/controlbus/ControlBusComponentConfigurer.java
b/components/camel-controlbus/src/generated/java/org/apache/camel/component/controlbus/ControlBusComponentConfigurer.java
index 0cef7a0fe01d..b06ee6bd19f4 100644
---
a/components/camel-controlbus/src/generated/java/org/apache/camel/component/controlbus/ControlBusComponentConfigurer.java
+++
b/components/camel-controlbus/src/generated/java/org/apache/camel/component/controlbus/ControlBusComponentConfigurer.java
@@ -24,6 +24,8 @@ public class ControlBusComponentConfigurer extends
PropertyConfigurerSupport imp
public boolean configure(CamelContext camelContext, Object obj, String
name, Object value, boolean ignoreCase) {
ControlBusComponent target = (ControlBusComponent) obj;
switch (ignoreCase ? name.toLowerCase(Locale.ROOT) : name) {
+ case "allowedlanguages":
+ case "allowedLanguages":
target.setAllowedLanguages(property(camelContext, java.lang.String.class,
value)); return true;
case "autowiredenabled":
case "autowiredEnabled":
target.setAutowiredEnabled(property(camelContext, boolean.class, value));
return true;
case "lazystartproducer":
@@ -35,6 +37,8 @@ public class ControlBusComponentConfigurer extends
PropertyConfigurerSupport imp
@Override
public Class<?> getOptionType(String name, boolean ignoreCase) {
switch (ignoreCase ? name.toLowerCase(Locale.ROOT) : name) {
+ case "allowedlanguages":
+ case "allowedLanguages": return java.lang.String.class;
case "autowiredenabled":
case "autowiredEnabled": return boolean.class;
case "lazystartproducer":
@@ -47,6 +51,8 @@ public class ControlBusComponentConfigurer extends
PropertyConfigurerSupport imp
public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
ControlBusComponent target = (ControlBusComponent) obj;
switch (ignoreCase ? name.toLowerCase(Locale.ROOT) : name) {
+ case "allowedlanguages":
+ case "allowedLanguages": return target.getAllowedLanguages();
case "autowiredenabled":
case "autowiredEnabled": return target.isAutowiredEnabled();
case "lazystartproducer":
diff --git
a/components/camel-controlbus/src/generated/java/org/apache/camel/component/controlbus/ControlBusEndpointConfigurer.java
b/components/camel-controlbus/src/generated/java/org/apache/camel/component/controlbus/ControlBusEndpointConfigurer.java
index 93dba1587fe4..47cb752b4a8b 100644
---
a/components/camel-controlbus/src/generated/java/org/apache/camel/component/controlbus/ControlBusEndpointConfigurer.java
+++
b/components/camel-controlbus/src/generated/java/org/apache/camel/component/controlbus/ControlBusEndpointConfigurer.java
@@ -25,6 +25,8 @@ public class ControlBusEndpointConfigurer extends
PropertyConfigurerSupport impl
ControlBusEndpoint target = (ControlBusEndpoint) obj;
switch (ignoreCase ? name.toLowerCase(Locale.ROOT) : name) {
case "action": target.setAction(property(camelContext,
java.lang.String.class, value)); return true;
+ case "allowedlanguages":
+ case "allowedLanguages":
target.setAllowedLanguages(property(camelContext, java.lang.String.class,
value)); return true;
case "async": target.setAsync(property(camelContext, boolean.class,
value)); return true;
case "lazystartproducer":
case "lazyStartProducer":
target.setLazyStartProducer(property(camelContext, boolean.class, value));
return true;
@@ -42,6 +44,8 @@ public class ControlBusEndpointConfigurer extends
PropertyConfigurerSupport impl
public Class<?> getOptionType(String name, boolean ignoreCase) {
switch (ignoreCase ? name.toLowerCase(Locale.ROOT) : name) {
case "action": return java.lang.String.class;
+ case "allowedlanguages":
+ case "allowedLanguages": return java.lang.String.class;
case "async": return boolean.class;
case "lazystartproducer":
case "lazyStartProducer": return boolean.class;
@@ -60,6 +64,8 @@ public class ControlBusEndpointConfigurer extends
PropertyConfigurerSupport impl
ControlBusEndpoint target = (ControlBusEndpoint) obj;
switch (ignoreCase ? name.toLowerCase(Locale.ROOT) : name) {
case "action": return target.getAction();
+ case "allowedlanguages":
+ case "allowedLanguages": return target.getAllowedLanguages();
case "async": return target.isAsync();
case "lazystartproducer":
case "lazyStartProducer": return target.isLazyStartProducer();
diff --git
a/components/camel-controlbus/src/generated/java/org/apache/camel/component/controlbus/ControlBusEndpointUriFactory.java
b/components/camel-controlbus/src/generated/java/org/apache/camel/component/controlbus/ControlBusEndpointUriFactory.java
index 41ba4fbd1e87..9c27494504bc 100644
---
a/components/camel-controlbus/src/generated/java/org/apache/camel/component/controlbus/ControlBusEndpointUriFactory.java
+++
b/components/camel-controlbus/src/generated/java/org/apache/camel/component/controlbus/ControlBusEndpointUriFactory.java
@@ -24,8 +24,9 @@ public class ControlBusEndpointUriFactory extends
org.apache.camel.support.compo
private static final Set<String> ENDPOINT_IDENTITY_PROPERTY_NAMES;
private static final Map<String, String> MULTI_VALUE_PREFIXES;
static {
- Set<String> props = new HashSet<>(8);
+ Set<String> props = new HashSet<>(9);
props.add("action");
+ props.add("allowedLanguages");
props.add("async");
props.add("command");
props.add("language");
diff --git
a/components/camel-controlbus/src/generated/resources/META-INF/org/apache/camel/component/controlbus/controlbus.json
b/components/camel-controlbus/src/generated/resources/META-INF/org/apache/camel/component/controlbus/controlbus.json
index 63dda925923f..2c0db8d547b4 100644
---
a/components/camel-controlbus/src/generated/resources/META-INF/org/apache/camel/component/controlbus/controlbus.json
+++
b/components/camel-controlbus/src/generated/resources/META-INF/org/apache/camel/component/controlbus/controlbus.json
@@ -25,7 +25,8 @@
},
"componentProperties": {
"lazyStartProducer": { "index": 0, "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 [...]
- "autowiredEnabled": { "index": 1, "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 t [...]
+ "autowiredEnabled": { "index": 1, "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 t [...]
+ "allowedLanguages": { "index": 2, "kind": "property", "displayName":
"Allowed Languages", "group": "security", "label": "security", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "description": "The names of the languages
the language command may use, separated by comma, such as simple. The language
command evaluates the message body as an expression, so it is off until the
language is in this list: a con [...]
},
"bodyTypes": {
"producerIn": { "carriers": [ "any" ], "byOption": [ { "option":
"command", "value": "language", "carriers": [ "text", "bytes", "stream", "file"
] } ], "description": "The route actions do not read the body. The language
command evaluates the body as its expression, as text" },
@@ -39,6 +40,7 @@
"loggingLevel": { "index": 4, "kind": "parameter", "displayName": "Logging
Level", "group": "producer", "label": "", "required": false, "type": "enum",
"javaType": "org.apache.camel.LoggingLevel", "enum": [ "TRACE", "DEBUG",
"INFO", "WARN", "ERROR", "OFF" ], "deprecated": false, "autowired": false,
"secret": false, "defaultValue": "INFO", "description": "Logging level used for
logging when task is done, or if any exceptions occurred during processing the
task." },
"restartDelay": { "index": 5, "kind": "parameter", "displayName": "Restart
Delay", "group": "producer", "label": "", "required": false, "type": "integer",
"javaType": "int", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": 1000, "description": "The delay in millis to use when
restarting a route." },
"routeId": { "index": 6, "kind": "parameter", "displayName": "Route Id",
"group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "description": "To specify a route by its id. The special
keyword current indicates the current route." },
- "lazyStartProducer": { "index": 7, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "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 produc [...]
+ "lazyStartProducer": { "index": 7, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "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 produc [...]
+ "allowedLanguages": { "index": 8, "kind": "parameter", "displayName":
"Allowed Languages", "group": "security", "label": "security", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "description": "The names of the languages
the language command may use, separated by comma, such as simple. The language
command evaluates the message body as an expression, so it is off until the
language is in this list: a co [...]
}
}
diff --git
a/components/camel-controlbus/src/main/docs/controlbus-component.adoc
b/components/camel-controlbus/src/main/docs/controlbus-component.adoc
index 05f6af24b0ce..e691bba99b5e 100644
--- a/components/camel-controlbus/src/main/docs/controlbus-component.adoc
+++ b/components/camel-controlbus/src/main/docs/controlbus-component.adoc
@@ -180,7 +180,29 @@ String xml =
template.requestBody("controlbus:route?action=stats", null, String.
=== Using Simple language
You can use the xref:languages:simple-language.adoc[Simple] language with the
control bus.
-For example, to stop a specific route, you can send a message to the
`"controlbus:language:simple"` endpoint containing the following message:
+
+The `language` command evaluates the message body as an expression, so it is
off by default.
+To turn it on, list the languages it may use in the `allowedLanguages` option,
separated by comma.
+Set it on the component to apply to every endpoint:
+
+[source,properties]
+----
+camel.component.controlbus.allowed-languages = simple
+----
+
+Or set it on the endpoint itself, which takes precedence over the list of the
component:
+
+[source,text]
+----
+controlbus:language:simple?allowedLanguages=simple
+----
+
+A `controlbus:language` endpoint whose language is not listed fails when it is
created, with an error that names the `allowedLanguages` option.
+The `route` command does not need this option.
+
+IMPORTANT: The body is evaluated as an expression with the full power of the
language: only send it text that comes from the route, never the content of a
message from an untrusted sender.
+
+With `simple` allowed on the component, to stop a specific route, you can send
a message to the `"controlbus:language:simple"` endpoint containing the
following message:
._Java-only: Java test API (ProducerTemplate)_
[source,java]
@@ -216,5 +238,5 @@ message we sent to the control bus component.
[TIP]
====
-You can also use other languages such as
xref:languages:groovy-language.adoc[Groovy], etc.
+You can also use other languages such as
xref:languages:groovy-language.adoc[Groovy], etc., when they are listed in the
`allowedLanguages` option.
====
diff --git
a/components/camel-controlbus/src/main/java/org/apache/camel/component/controlbus/ControlBusComponent.java
b/components/camel-controlbus/src/main/java/org/apache/camel/component/controlbus/ControlBusComponent.java
index 592cd4f3ca36..fbcf01850955 100644
---
a/components/camel-controlbus/src/main/java/org/apache/camel/component/controlbus/ControlBusComponent.java
+++
b/components/camel-controlbus/src/main/java/org/apache/camel/component/controlbus/ControlBusComponent.java
@@ -20,8 +20,10 @@ import java.util.Map;
import java.util.concurrent.ExecutorService;
import org.apache.camel.Endpoint;
+import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.annotations.Component;
import org.apache.camel.support.DefaultComponent;
+import org.apache.camel.util.ObjectHelper;
/**
* The <a href="http://camel.apache.org/controlbus.html">Control Bus
component</a> allows sending messages to a
@@ -30,25 +32,61 @@ import org.apache.camel.support.DefaultComponent;
@Component("controlbus")
public class ControlBusComponent extends DefaultComponent {
+ @Metadata(label = "security")
+ private String allowedLanguages;
+
private ExecutorService executorService;
public ControlBusComponent() {
}
+ public String getAllowedLanguages() {
+ return allowedLanguages;
+ }
+
+ /**
+ * The names of the languages the language command may use, separated by
comma, such as simple. The language command
+ * evaluates the message body as an expression, so it is off until the
language is in this list: a
+ * controlbus:language endpoint whose language is not listed fails when it
is created. The route actions are not
+ * affected. An endpoint can set its own list.
+ */
+ public void setAllowedLanguages(String allowedLanguages) {
+ this.allowedLanguages = allowedLanguages;
+ }
+
@Override
protected Endpoint createEndpoint(String uri, String remaining,
Map<String, Object> parameters) throws Exception {
ControlBusEndpoint answer = new ControlBusEndpoint(uri, this);
+ answer.setAllowedLanguages(allowedLanguages);
+ setProperties(answer, parameters);
// does the control bus use a language
if (remaining != null && remaining.startsWith("language:")) {
String lan = remaining.substring(9);
+ if (!isAllowedLanguage(answer.getAllowedLanguages(), lan)) {
+ throw new IllegalArgumentException(
+ "The language command of the control bus may not use
the " + lan + " language: add " + lan
+ + " to the allowedLanguages
option of the controlbus component or"
+ + " endpoint to turn it
on");
+ }
answer.setLanguage(getCamelContext().resolveLanguage(lan));
}
- setProperties(answer, parameters);
return answer;
}
+ private static boolean isAllowedLanguage(String allowedLanguages, String
language) {
+ if (ObjectHelper.isEmpty(allowedLanguages) ||
ObjectHelper.isEmpty(language)) {
+ return false;
+ }
+ for (String name : allowedLanguages.split(",")) {
+ if (name.trim().equals(language)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
ExecutorService getExecutorService() {
lock.lock();
try {
diff --git
a/components/camel-controlbus/src/main/java/org/apache/camel/component/controlbus/ControlBusEndpoint.java
b/components/camel-controlbus/src/main/java/org/apache/camel/component/controlbus/ControlBusEndpoint.java
index c15c643a35b3..9b7ca3b779bc 100644
---
a/components/camel-controlbus/src/main/java/org/apache/camel/component/controlbus/ControlBusEndpoint.java
+++
b/components/camel-controlbus/src/main/java/org/apache/camel/component/controlbus/ControlBusEndpoint.java
@@ -78,6 +78,8 @@ public class ControlBusEndpoint extends DefaultEndpoint {
private boolean async;
@UriParam(defaultValue = "INFO")
private LoggingLevel loggingLevel = LoggingLevel.INFO;
+ @UriParam(label = "security")
+ private String allowedLanguages;
private transient CamelLogger logger;
@@ -185,4 +187,18 @@ public class ControlBusEndpoint extends DefaultEndpoint {
public void setLoggingLevel(LoggingLevel loggingLevel) {
this.loggingLevel = loggingLevel;
}
+
+ public String getAllowedLanguages() {
+ return allowedLanguages;
+ }
+
+ /**
+ * The names of the languages the language command may use, separated by
comma, such as simple. The language command
+ * evaluates the message body as an expression, so it is off until the
language is in this list: a
+ * controlbus:language endpoint whose language is not listed fails when it
is created. The route actions are not
+ * affected. When not set, the list of the component is used.
+ */
+ public void setAllowedLanguages(String allowedLanguages) {
+ this.allowedLanguages = allowedLanguages;
+ }
}
diff --git
a/core/camel-core/src/test/java/org/apache/camel/component/controlbus/ControlBusLanguageAllowedTest.java
b/core/camel-core/src/test/java/org/apache/camel/component/controlbus/ControlBusLanguageAllowedTest.java
new file mode 100644
index 000000000000..81c186c86179
--- /dev/null
+++
b/core/camel-core/src/test/java/org/apache/camel/component/controlbus/ControlBusLanguageAllowedTest.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.controlbus;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.ResolveEndpointFailedException;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * The language command of the control bus is off until its language is in the
allowedLanguages option.
+ */
+public class ControlBusLanguageAllowedTest extends ContextTestSupport {
+
+ @Test
+ public void testLanguageOffByDefault() {
+ Exception e = assertThrows(Exception.class,
+ () -> context.getEndpoint("controlbus:language:simple"));
+ assertAllowedLanguagesError(e, "simple");
+ }
+
+ @Test
+ public void testLanguageNotInList() {
+ Exception e = assertThrows(Exception.class,
+ () ->
context.getEndpoint("controlbus:language:simple?allowedLanguages=groovy"));
+ assertAllowedLanguagesError(e, "simple");
+ }
+
+ @Test
+ public void testLanguageInEndpointList() {
+ String name =
template.requestBody("controlbus:language:simple?allowedLanguages=groovy,
simple",
+ "${camelContext.name}", String.class);
+ assertEquals(context.getName(), name);
+ }
+
+ @Test
+ public void testLanguageInComponentList() {
+ context.getComponent("controlbus",
ControlBusComponent.class).setAllowedLanguages("simple");
+
+ String name = template.requestBody("controlbus:language:simple",
"${camelContext.name}", String.class);
+ assertEquals(context.getName(), name);
+ }
+
+ @Test
+ public void testEndpointListOverridesComponentList() {
+ context.getComponent("controlbus",
ControlBusComponent.class).setAllowedLanguages("simple");
+
+ Exception e = assertThrows(Exception.class,
+ () ->
context.getEndpoint("controlbus:language:simple?allowedLanguages=constant"));
+ assertAllowedLanguagesError(e, "simple");
+ }
+
+ private static void assertAllowedLanguagesError(Exception e, String
language) {
+ ResolveEndpointFailedException re =
assertInstanceOf(ResolveEndpointFailedException.class, e);
+ Throwable cause = re.getCause();
+ assertInstanceOf(IllegalArgumentException.class, cause);
+ assertTrue(cause.getMessage().contains("allowedLanguages"),
cause.getMessage());
+ assertTrue(cause.getMessage().contains(" " + language + " "),
cause.getMessage());
+ }
+}
diff --git
a/core/camel-core/src/test/java/org/apache/camel/component/controlbus/ControlBusLanguageSimpleStartRouteTest.java
b/core/camel-core/src/test/java/org/apache/camel/component/controlbus/ControlBusLanguageSimpleStartRouteTest.java
index d6f81414b311..4e5a1aba6dd4 100644
---
a/core/camel-core/src/test/java/org/apache/camel/component/controlbus/ControlBusLanguageSimpleStartRouteTest.java
+++
b/core/camel-core/src/test/java/org/apache/camel/component/controlbus/ControlBusLanguageSimpleStartRouteTest.java
@@ -16,6 +16,7 @@
*/
package org.apache.camel.component.controlbus;
+import org.apache.camel.CamelContext;
import org.apache.camel.ContextTestSupport;
import org.apache.camel.builder.RouteBuilder;
import org.junit.jupiter.api.Test;
@@ -23,7 +24,7 @@ import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
- *
+ * The language command, turned on for simple with the allowedLanguages option
of the component.
*/
public class ControlBusLanguageSimpleStartRouteTest extends ContextTestSupport
{
@@ -62,6 +63,13 @@ public class ControlBusLanguageSimpleStartRouteTest extends
ContextTestSupport {
assertEquals("Started", status);
}
+ @Override
+ protected CamelContext createCamelContext() throws Exception {
+ CamelContext context = super.createCamelContext();
+ context.getComponent("controlbus",
ControlBusComponent.class).setAllowedLanguages("simple");
+ return context;
+ }
+
@Override
protected RouteBuilder createRouteBuilder() {
return new RouteBuilder() {
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index 8b6a06b99231..e60fe669b26c 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -20,6 +20,18 @@ was unavailable and `failOpen=true`. Previously this marker
was set only for sin
that inspect the marker after a batch should account for it applying to any
element; the per-element outcome
list identifies the affected elements. The existing `CamelOpaBatchDecision`
Boolean list is unchanged.
+=== camel-controlbus - the language command is off by default
+
+The `language` command of the control bus (`controlbus:language:<name>`)
evaluates the message body as an expression of the named language.
+It is now off by default: a `controlbus:language` endpoint fails when it is
created unless its language is listed in the new `allowedLanguages` option, on
the component or on the endpoint:
+
+[source,properties]
+----
+camel.component.controlbus.allowed-languages = simple
+----
+
+The `route` command (`controlbus:route?action=...`) is not affected.
+
=== camel-observability-services - promoted to Stable
The `camel-observability-services` component has been promoted from _Preview_
to _Stable_ support level.
diff --git
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/ControlbusComponentBuilderFactory.java
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/ControlbusComponentBuilderFactory.java
index 61c69d7dbe84..d185bc06feb2 100644
---
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/ControlbusComponentBuilderFactory.java
+++
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/ControlbusComponentBuilderFactory.java
@@ -96,6 +96,26 @@ public interface ControlbusComponentBuilderFactory {
doSetProperty("autowiredEnabled", autowiredEnabled);
return this;
}
+
+ /**
+ * The names of the languages the language command may use, separated
by
+ * comma, such as simple. The language command evaluates the message
+ * body as an expression, so it is off until the language is in this
+ * list: a controlbus:language endpoint whose language is not listed
+ * fails when it is created. The route actions are not affected. An
+ * endpoint can set its own list.
+ *
+ * The option is a: <code>java.lang.String</code> type.
+ *
+ * Group: security
+ *
+ * @param allowedLanguages the value to set
+ * @return the dsl builder
+ */
+ default ControlbusComponentBuilder allowedLanguages(java.lang.String
allowedLanguages) {
+ doSetProperty("allowedLanguages", allowedLanguages);
+ return this;
+ }
}
class ControlbusComponentBuilderImpl
@@ -113,6 +133,7 @@ public interface ControlbusComponentBuilderFactory {
switch (name) {
case "lazyStartProducer": ((ControlBusComponent)
component).setLazyStartProducer((boolean) value); return true;
case "autowiredEnabled": ((ControlBusComponent)
component).setAutowiredEnabled((boolean) value); return true;
+ case "allowedLanguages": ((ControlBusComponent)
component).setAllowedLanguages((java.lang.String) value); return true;
default: return false;
}
}
diff --git
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/ControlBusEndpointBuilderFactory.java
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/ControlBusEndpointBuilderFactory.java
index 4ab4b21fa479..480ec18aa0bb 100644
---
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/ControlBusEndpointBuilderFactory.java
+++
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/ControlBusEndpointBuilderFactory.java
@@ -178,6 +178,25 @@ public interface ControlBusEndpointBuilderFactory {
doSetProperty("routeId", routeId);
return this;
}
+ /**
+ * The names of the languages the language command may use, separated
by
+ * comma, such as simple. The language command evaluates the message
+ * body as an expression, so it is off until the language is in this
+ * list: a controlbus:language endpoint whose language is not listed
+ * fails when it is created. The route actions are not affected. When
+ * not set, the list of the component is used.
+ *
+ * The option is a: <code>java.lang.String</code> type.
+ *
+ * Group: security
+ *
+ * @param allowedLanguages the value to set
+ * @return the dsl builder
+ */
+ default ControlBusEndpointBuilder allowedLanguages(String
allowedLanguages) {
+ doSetProperty("allowedLanguages", allowedLanguages);
+ return this;
+ }
}
/**