Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,7 @@ stripe-component
stub-component
swiftMt-dataformat
swiftMx-dataformat
switch-eip
syslog-dataformat
tahu-edge-component
tahu-host-component
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
= Switch EIP
:doctitle: Switch
:shortname: switch
:description: Evaluates a selector once and dispatches to a fixed endpoint by literal scalar values
:since: 4.23
:supportlevel: Stable
:tabs-sync-option:

*Since Camel {since}*

Switch selects one destination from a table declared by the route author.
The selector can use any Camel expression language. Its result selects a case;
it cannot supply a new endpoint URI.

Use Switch for literal value dispatch. Use xref:choice-eip.adoc[Choice] for
predicates, ranges, overlapping conditions, or nested processing steps. A case can
send to a `direct:` route when more processing is needed. Use xref:toD-eip.adoc[To D]
when the endpoint URI itself must be calculated dynamically.

== Options

// eip options: START
include::partial$eip-options.adoc[]
// eip options: END

== Scalar selectors

The selector is evaluated once on each entry. Scalar results are converted to strings
and matched case-insensitively using the English locale. An empty string is a valid
literal. An asterisk is literal, not a wildcard. Duplicate normalized values are
rejected at startup.

Map, collection and array results are rejected with an `IllegalArgumentException`.
They follow normal Camel error handling and do not select `otherwise`.

=== Route from a header

This route reads the `department` header. The body is passed unchanged to the
selected destination. The examples on this page are independent; load one at a
time and connect the `direct:` destinations to your application's handling routes.

[tabs]
====
Java::
+
[source,java]
----
from("direct:tickets")
.doSwitch(header("department"))
.doCase("billing", "direct:billing")
.doCase("technical", "direct:technical")
.otherwise("direct:review")
.end();
----
XML::
+
[source,xml]
----
<route xmlns="http://camel.apache.org/schema/spring">
<from uri="direct:tickets"/>
<switch>
<selector><header>department</header></selector>
<case value="billing" uri="direct:billing"/>
<case value="technical" uri="direct:technical"/>
<otherwise uri="direct:review"/>
</switch>
</route>
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: direct:tickets
steps:
- switch:
selector:
header:
expression: department
case:
- value: billing
uri: direct:billing
- value: technical
uri: direct:technical
otherwise:
uri: direct:review
----
====

Send a message to any of these equivalent routes with a `ProducerTemplate`:

[source,java]
----
template.sendBodyAndHeader("direct:tickets", "Please check this invoice",
"department", "BILLING");
----

[cols="1,2",options="header"]
|===
|Header value |Destination
|`billing` or `BILLING` |`direct:billing`
|`technical` |`direct:technical`
|`sales` or an absent header |`direct:review`
|===

A null or unmatched result uses `otherwise`. Without `otherwise`, the exchange
continues after Switch. Selector failures follow normal Camel error handling and
never select the fallback. Streams are reset after selector evaluation when stream
caching is enabled. Loops and retries that enter Switch again evaluate the selector
again; results are not cached across entries.

=== Connect the example destinations

For a local demonstration, the destination routes can simply log the message.
Load these routes alongside one of the examples above; replace the logging steps
with the application's processing when integrating the example.

[tabs]
====
Java::
+
[source,java]
----
from("direct:billing").log("Billing: ${body}");
from("direct:technical").log("Technical: ${body}");
from("direct:review").log("Review: ${body}");
----
XML::
+
[source,xml]
----
<routes xmlns="http://camel.apache.org/schema/xml-io">
<route><from uri="direct:billing"/><log message="Billing: ${body}"/></route>
<route><from uri="direct:technical"/><log message="Technical: ${body}"/></route>
<route><from uri="direct:review"/><log message="Review: ${body}"/></route>
</routes>
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: direct:billing
steps:
- log: "Billing: ${body}"
- route:
from:
uri: direct:technical
steps:
- log: "Technical: ${body}"
- route:
from:
uri: direct:review
steps:
- log: "Review: ${body}"
----
====

== Destinations and management

Case and fallback URIs support property placeholders resolved at startup. Simple
expressions in URIs are rejected. In YAML, both cases and `otherwise` accept `uri`
plus `parameters`:

[source,yaml]
----
case:
- value: orders
uri: kafka
parameters:
topic: orders
otherwise:
uri: direct
parameters:
name: review
----

Each case has an identity for tracing, debugging and management. The Switch MBean's
`extendedInformation` table reports case IDs, literal values, destination URIs and
selection counts. URIs are masked when management masking is enabled (the default).
These counts indicate case selection, not successful delivery.
`UnmatchedCount` also records unmatched results when no fallback is configured.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ beanio
bearerToken
bindy
cache
case
cbor
choice
circuitBreaker
Expand Down Expand Up @@ -196,6 +197,8 @@ stop
streamConfig
swiftMt
swiftMx
switch
switchOtherwise
syslog
tarFile
templateParameter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@
"emitAfter": { "index": 5, "kind": "attribute", "displayName": "Emit After", "group": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Simple expression template to emit after the nested steps complete successfully" },
"emitOnError": { "index": 6, "kind": "attribute", "displayName": "Emit On Error", "group": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Simple expression template to emit when the nested steps fail" },
"failIfNoTaskContext": { "index": 7, "kind": "attribute", "displayName": "Fail If No Task Context", "group": "common", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to fail if the current Exchange does not have an active A2A task context" },
"outputs": { "index": 8, "kind": "element", "displayName": "Outputs", "group": "common", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "a2aSubTask", "aggregate", "bean", "cache", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "convertVariableTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onException", "pausable", "pipeline", "policy", "poll", "pollEnrich", "process", "recipientList", "removeHeader", "removeHeaders", "removeProperties", "removeProperty", "removeVariable", "resequence", "resumable", "rollback", "routingSlip", "saga", "sample", "script", "setBody", "setExchangePattern", "setHeader", "setHeaders", "setProperty", "setVariable", "setVariables", "sort", "split", "step", "stop", "threads", "throttle", "throwException", "to", "toD", "tokenizer", "transacted", "transform", "transformDataType", "unmarshal", "validate", "wireTap" ], "deprecated": false, "autowired": false, "secret": false }
"outputs": { "index": 8, "kind": "element", "displayName": "Outputs", "group": "common", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "a2aSubTask", "aggregate", "bean", "cache", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "convertVariableTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onException", "pausable", "pipeline", "policy", "poll", "pollEnrich", "process", "recipientList", "removeHeader", "removeHeaders", "removeProperties", "removeProperty", "removeVariable", "resequence", "resumable", "rollback", "routingSlip", "saga", "sample", "script", "setBody", "setExchangePattern", "setHeader", "setHeaders", "setProperty", "setVariable", "setVariables", "sort", "split", "step", "stop", "switch", "threads", "throttle", "throwException", "to", "toD", "tokenizer", "transacted", "transform", "transformDataType", "unmarshal", "validate", "wireTap" ], "deprecated": false, "autowired": false, "secret": false }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"discardOnAggregationFailure": { "index": 29, "kind": "attribute", "displayName": "Discard On Aggregation Failure", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If enabled then the partly aggregated message is discarded when aggregation failed (an exception was thrown from AggregationStrategy). Cannot be used together with completionFromBatchConsumer." },
"forceCompletionOnStop": { "index": 30, "kind": "attribute", "displayName": "Force Completion On Stop", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If enabled then all current aggregated exchanges are completed when the context is stopped." },
"completeAllOnStop": { "index": 31, "kind": "attribute", "displayName": "Complete All On Stop", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If enabled then waits to complete all current and partial (pending) aggregated exchanges when the context is stopped, ensuring the aggregation repository is empty before shutdown." },
"outputs": { "index": 32, "kind": "element", "displayName": "Outputs", "group": "common", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "a2aSubTask", "aggregate", "bean", "cache", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "convertVariableTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onException", "pausable", "pipeline", "policy", "poll", "pollEnrich", "process", "recipientList", "removeHeader", "removeHeaders", "removeProperties", "removeProperty", "removeVariable", "resequence", "resumable", "rollback", "routingSlip", "saga", "sample", "script", "setBody", "setExchangePattern", "setHeader", "setHeaders", "setProperty", "setVariable", "setVariables", "sort", "split", "step", "stop", "threads", "throttle", "throwException", "to", "toD", "tokenizer", "transacted", "transform", "transformDataType", "unmarshal", "validate", "wireTap" ], "deprecated": false, "autowired": false, "secret": false }
"outputs": { "index": 32, "kind": "element", "displayName": "Outputs", "group": "common", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "a2aSubTask", "aggregate", "bean", "cache", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "convertVariableTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onException", "pausable", "pipeline", "policy", "poll", "pollEnrich", "process", "recipientList", "removeHeader", "removeHeaders", "removeProperties", "removeProperty", "removeVariable", "resequence", "resumable", "rollback", "routingSlip", "saga", "sample", "script", "setBody", "setExchangePattern", "setHeader", "setHeaders", "setProperty", "setVariable", "setVariables", "sort", "split", "step", "stop", "switch", "threads", "throttle", "throwException", "to", "toD", "tokenizer", "transacted", "transform", "transformDataType", "unmarshal", "validate", "wireTap" ], "deprecated": false, "autowired": false, "secret": false }
},
"exchangeProperties": {
"CamelAggregatedSize": { "index": 0, "kind": "exchangeProperty", "displayName": "Aggregated Size", "label": "producer", "required": false, "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "important": true, "description": "Number of exchanges that was grouped together." },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@
"keyValueRepository": { "index": 5, "kind": "attribute", "displayName": "Key Value Repository", "group": "common", "required": false, "type": "object", "javaType": "org.apache.camel.spi.KeyValueRepository", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the reference name of the KeyValueRepository to use as the cache backing store. If not set, a MemoryKeyValueRepository is auto-created." },
"ttl": { "index": 6, "kind": "attribute", "displayName": "Ttl", "group": "common", "required": false, "type": "duration", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "-1", "description": "Sets the time-to-live for cached entries. Supports duration syntax (e.g. 10m, 1h) or milliseconds. Default: -1 (no expiration)." },
"cacheNull": { "index": 7, "kind": "attribute", "displayName": "Cache Null", "group": "common", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to cache null results. By default, null message bodies are not cached." },
"outputs": { "index": 8, "kind": "element", "displayName": "Outputs", "group": "common", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "a2aSubTask", "aggregate", "bean", "cache", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "convertVariableTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onException", "pausable", "pipeline", "policy", "poll", "pollEnrich", "process", "recipientList", "removeHeader", "removeHeaders", "removeProperties", "removeProperty", "removeVariable", "resequence", "resumable", "rollback", "routingSlip", "saga", "sample", "script", "setBody", "setExchangePattern", "setHeader", "setHeaders", "setProperty", "setVariable", "setVariables", "sort", "split", "step", "stop", "threads", "throttle", "throwException", "to", "toD", "tokenizer", "transacted", "transform", "transformDataType", "unmarshal", "validate", "wireTap" ], "deprecated": false, "autowired": false, "secret": false }
"outputs": { "index": 8, "kind": "element", "displayName": "Outputs", "group": "common", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "a2aSubTask", "aggregate", "bean", "cache", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "convertVariableTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onException", "pausable", "pipeline", "policy", "poll", "pollEnrich", "process", "recipientList", "removeHeader", "removeHeaders", "removeProperties", "removeProperty", "removeVariable", "resequence", "resumable", "rollback", "routingSlip", "saga", "sample", "script", "setBody", "setExchangePattern", "setHeader", "setHeaders", "setProperty", "setVariable", "setVariables", "sort", "split", "step", "stop", "switch", "threads", "throttle", "throwException", "to", "toD", "tokenizer", "transacted", "transform", "transformDataType", "unmarshal", "validate", "wireTap" ], "deprecated": false, "autowired": false, "secret": false }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"model": {
"kind": "model",
"name": "case",
"title": "Case",
"description": "A literal switch case with one fixed endpoint destination",
"deprecated": false,
"label": "configuration",
"javaType": "org.apache.camel.model.SwitchCaseDefinition",
"abstract": false,
"input": false,
"output": false
},
"properties": {
"id": { "index": 0, "kind": "attribute", "displayName": "Id", "group": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The id of this node" },
"note": { "index": 1, "kind": "attribute", "displayName": "Note", "group": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The note for this node" },
"description": { "index": 2, "kind": "attribute", "displayName": "Description", "group": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The description for this node" },
"value": { "index": 3, "kind": "attribute", "displayName": "Value", "group": "common", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The case-insensitive literal value for a scalar selector." },
"uri": { "index": 4, "kind": "attribute", "displayName": "Uri", "group": "common", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The fixed destination URI. Supports property placeholders, but not Simple expressions." }
}
}
Loading
Loading