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-jbang-examples.git
The following commit(s) were added to refs/heads/main by this push:
new 56016bb CAMEL-24808: rung 3 of the ladder: route (#79)
56016bb is described below
commit 56016bb22783a4370e2090dfef78447788f6188f
Author: Claus Ibsen <[email protected]>
AuthorDate: Fri Sep 18 16:37:12 2026 +0200
CAMEL-24808: rung 3 of the ladder: route (#79)
Four examples under route/, all reading the same three web shop orders from
an orders/ directory: content-based-router (choice by country, moved from
eip/), order-lines (split with the order id in a header), aggregator (lines
back into a shipment with GroupedBodyAggregationStrategy, moved from eip/) and
filter-and-multicast (paid orders to warehouse and invoicing). Each has a
README in the ladder shape, metadata with teaches, a Citrus YAML test run by
camel test, and a CI matrix entry.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Bp3538HRBPMQkb5ta9xRaj
---
.github/workflows/build.yml | 8 +
camel-jbang-example-catalog.json | 236 +++++++++++++++------
eip/aggregator/README.md | 47 ----
eip/aggregator/aggregator.camel.yaml | 37 ----
eip/aggregator/metadata.json | 25 ---
eip/content-based-router/README.md | 48 -----
.../content-based-router.camel.yaml | 47 ----
eip/content-based-router/metadata.json | 25 ---
route/aggregator/README.md | 72 +++++++
route/aggregator/aggregator.camel.yaml | 52 +++++
route/aggregator/application.properties | 16 ++
route/aggregator/metadata.json | 32 +++
route/aggregator/orders/order-1001.json | 2 +
route/aggregator/orders/order-1002.json | 2 +
route/aggregator/orders/order-1003.json | 2 +
route/aggregator/test/aggregator.citrus.it.yaml | 25 +++
route/content-based-router/README.md | 66 ++++++
route/content-based-router/application.properties | 16 ++
.../content-based-router.camel.yaml | 33 +++
route/content-based-router/metadata.json | 28 +++
route/content-based-router/orders/order-1001.json | 2 +
route/content-based-router/orders/order-1002.json | 2 +
route/content-based-router/orders/order-1003.json | 2 +
.../test/content-based-router.citrus.it.yaml | 30 +++
route/filter-and-multicast/README.md | 68 ++++++
route/filter-and-multicast/application.properties | 16 ++
.../filter-and-multicast.camel.yaml | 50 +++++
route/filter-and-multicast/metadata.json | 30 +++
route/filter-and-multicast/orders/order-1001.json | 2 +
route/filter-and-multicast/orders/order-1002.json | 2 +
route/filter-and-multicast/orders/order-1003.json | 2 +
.../test/filter-and-multicast.citrus.it.yaml | 30 +++
route/order-lines/README.md | 71 +++++++
route/order-lines/application.properties | 16 ++
route/order-lines/metadata.json | 29 +++
route/order-lines/order-lines.camel.yaml | 30 +++
route/order-lines/orders/order-1001.json | 2 +
route/order-lines/orders/order-1002.json | 2 +
route/order-lines/orders/order-1003.json | 2 +
route/order-lines/test/order-lines.citrus.it.yaml | 25 +++
40 files changed, 933 insertions(+), 299 deletions(-)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 2cb9c54..09d8559 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -50,6 +50,14 @@ jobs:
path: transform/groovy
- name: XSLT
path: transform/xslt
+ - name: Content-based router
+ path: route/content-based-router
+ - name: Order lines
+ path: route/order-lines
+ - name: Aggregator
+ path: route/aggregator
+ - name: Filter and multicast
+ path: route/filter-and-multicast
- name: OpenAPI server
path: rest/openapi-server
- name: OpenAPI client
diff --git a/camel-jbang-example-catalog.json b/camel-jbang-example-catalog.json
index 909c4b7..4a5e588 100644
--- a/camel-jbang-example-catalog.json
+++ b/camel-jbang-example-catalog.json
@@ -373,38 +373,6 @@
"postgres"
]
},
- {
- "name": "eip/aggregator",
- "title": "Aggregator",
- "description": "A timer sends individual messages that the aggregator
collects into a batch of three by a correlation key, and one log line shows
each completed batch.",
- "level": "route",
- "teaches": {
- "components": [
- "timer",
- "direct",
- "log"
- ],
- "eips": [
- "aggregate",
- "bean"
- ],
- "languages": [
- "simple"
- ]
- },
- "tags": [
- "eip",
- "aggregator",
- "batch"
- ],
- "bundled": true,
- "requiresDocker": false,
- "hasCitrusTests": false,
- "files": [
- "README.md",
- "aggregator.camel.yaml"
- ]
- },
{
"name": "eip/circuit-breaker",
"title": "Circuit Breaker",
@@ -439,38 +407,6 @@
"route.camel.yaml"
]
},
- {
- "name": "eip/content-based-router",
- "title": "Content Based Router",
- "description": "A timer produces messages with different content and a
choice routes each to a different branch by its content, so the log shows which
branch handled which message.",
- "level": "route",
- "teaches": {
- "components": [
- "timer",
- "log"
- ],
- "eips": [
- "choice",
- "setHeader",
- "convertBodyTo"
- ],
- "languages": [
- "simple"
- ]
- },
- "tags": [
- "eip",
- "choice",
- "routing"
- ],
- "bundled": true,
- "requiresDocker": false,
- "hasCitrusTests": false,
- "files": [
- "README.md",
- "content-based-router.camel.yaml"
- ]
- },
{
"name": "eip/splitter",
"title": "Splitter",
@@ -772,6 +708,169 @@
"petstore.camel.yaml"
]
},
+ {
+ "name": "route/aggregator",
+ "title": "Aggregator",
+ "description": "The warehouse reports each picked line on its own and
the aggregator collects the lines of one order back into a shipment, correlated
by the order id and complete when as many lines are in as the order had; each
shipment is logged as JSON.",
+ "level": "route",
+ "teaches": {
+ "components": [
+ "file",
+ "direct",
+ "log"
+ ],
+ "eips": [
+ "aggregate",
+ "split",
+ "setHeader",
+ "marshal",
+ "unmarshal"
+ ],
+ "languages": [
+ "simple"
+ ],
+ "dataformats": [
+ "json"
+ ]
+ },
+ "tags": [
+ "shop",
+ "eip",
+ "aggregator",
+ "batch"
+ ],
+ "bundled": false,
+ "requiresDocker": false,
+ "hasCitrusTests": true,
+ "files": [
+ "README.md",
+ "aggregator.camel.yaml",
+ "application.properties",
+ "orders/order-1001.json",
+ "orders/order-1002.json",
+ "orders/order-1003.json"
+ ]
+ },
+ {
+ "name": "route/content-based-router",
+ "title": "Content-based router",
+ "description": "Three orders from three countries are read from the
orders directory and a choice routes each by its country: the Danish order to
local delivery, the German order to EU shipping without customs, the US order
to export with a customs declaration; each branch logs what it did.",
+ "level": "route",
+ "teaches": {
+ "components": [
+ "file",
+ "log"
+ ],
+ "eips": [
+ "choice",
+ "unmarshal"
+ ],
+ "languages": [
+ "simple"
+ ],
+ "dataformats": [
+ "json"
+ ]
+ },
+ "tags": [
+ "shop",
+ "eip",
+ "choice",
+ "routing"
+ ],
+ "bundled": false,
+ "requiresDocker": false,
+ "hasCitrusTests": true,
+ "files": [
+ "README.md",
+ "application.properties",
+ "content-based-router.camel.yaml",
+ "orders/order-1001.json",
+ "orders/order-1002.json",
+ "orders/order-1003.json"
+ ]
+ },
+ {
+ "name": "route/filter-and-multicast",
+ "title": "Filter and multicast",
+ "description": "Three orders are read from the orders directory; a
filter lets only the paid ones through and a multicast sends each paid order to
both the warehouse route and the invoicing route, which log their part; the
pending order is logged as received and goes no further.",
+ "level": "route",
+ "teaches": {
+ "components": [
+ "file",
+ "direct",
+ "log"
+ ],
+ "eips": [
+ "filter",
+ "multicast",
+ "unmarshal"
+ ],
+ "languages": [
+ "simple"
+ ],
+ "dataformats": [
+ "json"
+ ]
+ },
+ "tags": [
+ "shop",
+ "eip",
+ "filter",
+ "multicast"
+ ],
+ "bundled": false,
+ "requiresDocker": false,
+ "hasCitrusTests": true,
+ "files": [
+ "README.md",
+ "application.properties",
+ "filter-and-multicast.camel.yaml",
+ "orders/order-1001.json",
+ "orders/order-1002.json",
+ "orders/order-1003.json"
+ ]
+ },
+ {
+ "name": "route/order-lines",
+ "title": "Order lines",
+ "description": "Each order read from the orders directory is split
into one message per line, the order id travels along in a header, and the log
shows the order, one pick line per line, and the parent's confirmation that all
lines went to picking.",
+ "level": "route",
+ "teaches": {
+ "components": [
+ "file",
+ "log"
+ ],
+ "eips": [
+ "split",
+ "setHeader",
+ "unmarshal"
+ ],
+ "languages": [
+ "simple"
+ ],
+ "dataformats": [
+ "json"
+ ]
+ },
+ "tags": [
+ "shop",
+ "eip",
+ "splitter",
+ "split"
+ ],
+ "bundled": false,
+ "requiresDocker": false,
+ "hasCitrusTests": true,
+ "files": [
+ "README.md",
+ "application.properties",
+ "order-lines.camel.yaml",
+ "orders/order-1001.json",
+ "orders/order-1002.json",
+ "orders/order-1003.json"
+ ]
+ },
{
"name": "run/nightly-report",
"title": "Nightly report",
@@ -944,10 +1043,7 @@
"README.md",
"application.properties",
"csv-to-json.camel.yaml",
- "inbox/invoices.csv",
- "outbox/INV-2001.json",
- "outbox/INV-2002.json",
- "outbox/INV-2003.json"
+ "inbox/invoices.csv"
]
},
{
@@ -1022,7 +1118,7 @@
],
"bundled": false,
"requiresDocker": false,
- "hasCitrusTests": false,
+ "hasCitrusTests": true,
"files": [
"README.md",
"application.properties",
@@ -1129,7 +1225,7 @@
],
"bundled": false,
"requiresDocker": false,
- "hasCitrusTests": false,
+ "hasCitrusTests": true,
"files": [
"README.md",
"application.properties",
diff --git a/eip/aggregator/README.md b/eip/aggregator/README.md
deleted file mode 100644
index 2f66737..0000000
--- a/eip/aggregator/README.md
+++ /dev/null
@@ -1,47 +0,0 @@
-## Aggregator
-
-This example demonstrates the Aggregator EIP.
-
-Individual order messages are collected into batches of 5 using the Aggregator
EIP.
-The `StringAggregationStrategy` joins message bodies with a comma delimiter.
-
-A timer generates one order per second. The aggregator collects 5 orders before
-releasing the batch, which is then logged as a single combined message.
-
-### Install JBang
-
-First install JBang according to https://www.jbang.dev
-
-When JBang is installed then you should be able to run from a shell:
-
-```sh
-$ jbang --version
-```
-
-This will output the version of JBang.
-
-To run this example you can either install Camel on JBang via:
-
-```sh
-$ jbang app install camel@apache/camel
-```
-
-Which allows to run Camel CLI with `camel` as shown below.
-
-### How to run
-
-You can run this example using:
-
-```sh
-$ camel run *
-```
-
-### Help and contributions
-
-If you hit any problem using Camel or have some feedback, then please
-[let us know](https://camel.apache.org/community/support/).
-
-We also love contributors, so
-[get involved](https://camel.apache.org/community/contributing/) :-)
-
-The Camel riders!
diff --git a/eip/aggregator/aggregator.camel.yaml
b/eip/aggregator/aggregator.camel.yaml
deleted file mode 100644
index 45a750c..0000000
--- a/eip/aggregator/aggregator.camel.yaml
+++ /dev/null
@@ -1,37 +0,0 @@
-- beans:
- - name: myAggregationStrategy
- type:
"#class:org.apache.camel.processor.aggregate.StringAggregationStrategy"
- properties:
- delimiter: ", "
-
-- route:
- id: order-generator
- from:
- uri: timer
- parameters:
- timerName: orders
- period: 1000
- steps:
- - setBody:
- expression:
- simple:
- expression: "Order-${exchangeProperty.CamelTimerCounter}"
- - log:
- message: "New: ${body}"
- - to:
- uri: direct:aggregate
-
-- route:
- id: order-aggregator
- from:
- uri: direct:aggregate
- steps:
- - aggregate:
- aggregationStrategy: "#bean:myAggregationStrategy"
- correlationExpression:
- constant:
- expression: "true"
- completionSize: 5
- steps:
- - log:
- message: "Batch of 5: ${body}"
diff --git a/eip/aggregator/metadata.json b/eip/aggregator/metadata.json
deleted file mode 100644
index 485c8c6..0000000
--- a/eip/aggregator/metadata.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "title": "Aggregator",
- "description": "A timer sends individual messages that the aggregator
collects into a batch of three by a correlation key, and one log line shows
each completed batch.",
- "level": "route",
- "teaches": {
- "components": [
- "timer",
- "direct",
- "log"
- ],
- "eips": [
- "aggregate",
- "bean"
- ],
- "languages": [
- "simple"
- ]
- },
- "tags": [
- "eip",
- "aggregator",
- "batch"
- ],
- "bundled": true
-}
diff --git a/eip/content-based-router/README.md
b/eip/content-based-router/README.md
deleted file mode 100644
index d030d8d..0000000
--- a/eip/content-based-router/README.md
+++ /dev/null
@@ -1,48 +0,0 @@
-## Content Based Router
-
-This example demonstrates the Content Based Router EIP.
-
-A simulated temperature sensor generates random readings between 0 and 40.
-The route uses the `choice` EIP to classify each reading:
-
-- **Hot** (>= 30): logged as an alert
-- **Normal** (15-29): logged as normal
-- **Cold** (< 15): logged as an alert
-
-### Install JBang
-
-First install JBang according to https://www.jbang.dev
-
-When JBang is installed then you should be able to run from a shell:
-
-```sh
-$ jbang --version
-```
-
-This will output the version of JBang.
-
-To run this example you can either install Camel on JBang via:
-
-```sh
-$ jbang app install camel@apache/camel
-```
-
-Which allows to run Camel CLI with `camel` as shown below.
-
-### How to run
-
-You can run this example using:
-
-```sh
-$ camel run *
-```
-
-### Help and contributions
-
-If you hit any problem using Camel or have some feedback, then please
-[let us know](https://camel.apache.org/community/support/).
-
-We also love contributors, so
-[get involved](https://camel.apache.org/community/contributing/) :-)
-
-The Camel riders!
diff --git a/eip/content-based-router/content-based-router.camel.yaml
b/eip/content-based-router/content-based-router.camel.yaml
deleted file mode 100644
index d451fcf..0000000
--- a/eip/content-based-router/content-based-router.camel.yaml
+++ /dev/null
@@ -1,47 +0,0 @@
-- route:
- id: sensor
- from:
- uri: timer
- parameters:
- timerName: sensor
- period: 1000
- steps:
- - setBody:
- expression:
- simple:
- expression: "${random(0,40)}"
- - convertBodyTo:
- type: int
- - choice:
- when:
- - expression:
- simple:
- expression: "${body} >= 30"
- steps:
- - setHeader:
- name: level
- expression:
- constant:
- expression: hot
- - log:
- message: "Hot alert: ${body} C"
- - expression:
- simple:
- expression: "${body} >= 15"
- steps:
- - setHeader:
- name: level
- expression:
- constant:
- expression: normal
- - log:
- message: "Normal: ${body} C"
- otherwise:
- steps:
- - setHeader:
- name: level
- expression:
- constant:
- expression: cold
- - log:
- message: "Cold alert: ${body} C"
diff --git a/eip/content-based-router/metadata.json
b/eip/content-based-router/metadata.json
deleted file mode 100644
index 127d7b3..0000000
--- a/eip/content-based-router/metadata.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "title": "Content Based Router",
- "description": "A timer produces messages with different content and a
choice routes each to a different branch by its content, so the log shows which
branch handled which message.",
- "level": "route",
- "teaches": {
- "components": [
- "timer",
- "log"
- ],
- "eips": [
- "choice",
- "setHeader",
- "convertBodyTo"
- ],
- "languages": [
- "simple"
- ]
- },
- "tags": [
- "eip",
- "choice",
- "routing"
- ],
- "bundled": true
-}
diff --git a/route/aggregator/README.md b/route/aggregator/README.md
new file mode 100644
index 0000000..d67c6fb
--- /dev/null
+++ b/route/aggregator/README.md
@@ -0,0 +1,72 @@
+# Aggregator
+
+The reverse of `order-lines`: the warehouse reports each picked line on its
own, and the aggregator collects the
+lines of one order back into a shipment. Lines are correlated by the order id,
and a shipment completes when all
+the lines the order had are in.
+
+## What you will see
+
+```text
+INFO ... aggregator.camel.yaml:26 : Picked 2 x CAMEL-TSHIRT for ORD-1001
+INFO ... aggregator.camel.yaml:26 : Picked 1 x CAMEL-MUG for ORD-1001
+INFO ... aggregator.camel.yaml:26 : Picked 3 x CAMEL-MUG for ORD-1002
+...
+INFO ... aggregator.camel.yaml:51 : Shipment for ORD-1001 complete:
[{"sku":"CAMEL-TSHIRT","qty":2,"price":19.95},{"sku":"CAMEL-MUG","qty":1,"price":9.5}]
+INFO ... aggregator.camel.yaml:51 : Shipment for ORD-1002 complete:
[{"sku":"CAMEL-MUG","qty":3,"price":9.5}]
+```
+
+## Install Camel CLI
+
+<!-- see installation instructions in ../../install.adoc -->
+
+## Run it
+
+```shell
+camel run *
+```
+
+The three orders in `orders/` are read once each (`noop: true` leaves the
files in place), so the run
+can be repeated.
+
+## How it works
+
+- The first route reads the orders, keeps the order id in a header, splits
them into lines, and sends every
+ line to `direct:shipment`, as a warehouse system would report picks one by
one.
+- The second route aggregates: `correlationExpression` `${header.orderId}`
groups lines of the same order,
+ `completionSizeExpression` `${header.CamelSplitSize}` says how many lines
make the order complete, and the
+ `GroupedBodyAggregationStrategy` collects the bodies into a list.
+- When a shipment completes, the list of lines is written as JSON with
`marshal` and logged.
+
+## Build it step by step
+
+1. Start from `order-lines` and send each line to `direct:shipment` instead of
only logging it.
+2. Add a route from `direct:shipment` with an `aggregate` correlating on
`${header.orderId}` and a fixed
+ `completionSize: 2`; only the two-line order completes.
+3. Replace the fixed size by `completionSizeExpression` with
`${header.CamelSplitSize}`.
+4. Add `marshal` with `json` and log the shipment.
+
+## Try changing
+
+- Add `completionTimeout: 5000` so a shipment with a missing line still closes
after five seconds.
+- Sum the pieces instead of listing the lines: the `data-mapping` example
shows the Groovy for it.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/)
YAML DSL,
+`test/aggregator.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/aggregator.citrus.it.yaml
+```
+
+The test starts the route and verifies that the shipments for the three orders
complete.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/route/aggregator/aggregator.camel.yaml
b/route/aggregator/aggregator.camel.yaml
new file mode 100644
index 0000000..5148ba5
--- /dev/null
+++ b/route/aggregator/aggregator.camel.yaml
@@ -0,0 +1,52 @@
+# The reverse of order-lines: the warehouse reports each picked line on its
own, and the aggregator
+# collects the lines of one order back into a shipment. Lines are correlated
by the order id, and a
+# shipment completes when all the lines the order had are in.
+- route:
+ id: picked-lines
+ from:
+ uri: file
+ parameters:
+ directoryName: orders
+ noop: true
+ sortBy: "file:name"
+ steps:
+ - unmarshal:
+ json:
+ library: Jackson
+ - setHeader:
+ name: orderId
+ expression:
+ simple:
+ expression: "${body[orderId]}"
+ - split:
+ expression:
+ simple:
+ expression: "${body[lines]}"
+ steps:
+ - log:
+ message: "Picked ${body[qty]} x ${body[sku]} for
${header.orderId}"
+ - to:
+ uri: direct
+ parameters:
+ name: shipment
+- route:
+ id: aggregator
+ from:
+ uri: direct
+ parameters:
+ name: shipment
+ steps:
+ - aggregate:
+ aggregationStrategy:
"#class:org.apache.camel.processor.aggregate.GroupedBodyAggregationStrategy"
+ correlationExpression:
+ simple:
+ expression: "${header.orderId}"
+ completionSizeExpression:
+ simple:
+ expression: "${header.CamelSplitSize}"
+ steps:
+ - marshal:
+ json:
+ library: Jackson
+ - log:
+ message: "Shipment for ${header.orderId} complete: ${body}"
diff --git a/route/aggregator/application.properties
b/route/aggregator/application.properties
new file mode 100644
index 0000000..13a8339
--- /dev/null
+++ b/route/aggregator/application.properties
@@ -0,0 +1,16 @@
+# 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.
diff --git a/route/aggregator/metadata.json b/route/aggregator/metadata.json
new file mode 100644
index 0000000..9fc6469
--- /dev/null
+++ b/route/aggregator/metadata.json
@@ -0,0 +1,32 @@
+{
+ "title": "Aggregator",
+ "description": "The warehouse reports each picked line on its own and the
aggregator collects the lines of one order back into a shipment, correlated by
the order id and complete when as many lines are in as the order had; each
shipment is logged as JSON.",
+ "level": "route",
+ "teaches": {
+ "components": [
+ "file",
+ "direct",
+ "log"
+ ],
+ "eips": [
+ "aggregate",
+ "split",
+ "setHeader",
+ "marshal",
+ "unmarshal"
+ ],
+ "languages": [
+ "simple"
+ ],
+ "dataformats": [
+ "json"
+ ]
+ },
+ "tags": [
+ "shop",
+ "eip",
+ "aggregator",
+ "batch"
+ ],
+ "bundled": false
+}
diff --git a/route/aggregator/orders/order-1001.json
b/route/aggregator/orders/order-1001.json
new file mode 100644
index 0000000..3eb5f03
--- /dev/null
+++ b/route/aggregator/orders/order-1001.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1001", "customer": "C-482", "country": "DK", "status": "paid",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 2, "price": 19.95}, {"sku":
"CAMEL-MUG", "qty": 1, "price": 9.50}]}
diff --git a/route/aggregator/orders/order-1002.json
b/route/aggregator/orders/order-1002.json
new file mode 100644
index 0000000..bb7aa0e
--- /dev/null
+++ b/route/aggregator/orders/order-1002.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1002", "customer": "C-207", "country": "DE", "status": "paid",
+ "lines": [{"sku": "CAMEL-MUG", "qty": 3, "price": 9.50}]}
diff --git a/route/aggregator/orders/order-1003.json
b/route/aggregator/orders/order-1003.json
new file mode 100644
index 0000000..9edab76
--- /dev/null
+++ b/route/aggregator/orders/order-1003.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1003", "customer": "C-134", "country": "US", "status":
"pending",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 1, "price": 19.95}, {"sku":
"CAMEL-CAP", "qty": 1, "price": 14.00}, {"sku": "CAMEL-MUG", "qty": 2, "price":
9.50}]}
diff --git a/route/aggregator/test/aggregator.citrus.it.yaml
b/route/aggregator/test/aggregator.citrus.it.yaml
new file mode 100644
index 0000000..9d7e783
--- /dev/null
+++ b/route/aggregator/test/aggregator.citrus.it.yaml
@@ -0,0 +1,25 @@
+name: aggregator-test
+description: The aggregator example logs what its README promises
+actions:
+ - camel:
+ jbang:
+ run:
+ integration:
+ name: "aggregator"
+ file: "../aggregator.camel.yaml"
+ systemProperties:
+ file: "../application.properties"
+ resources:
+ - "orders/order-1001.json"
+ - "orders/order-1002.json"
+ - "orders/order-1003.json"
+ - camel:
+ jbang:
+ verify:
+ integration: "aggregator"
+ logMessage: "Shipment for ORD-1001 complete"
+ - camel:
+ jbang:
+ verify:
+ integration: "aggregator"
+ logMessage: "Shipment for ORD-1003 complete"
diff --git a/route/content-based-router/README.md
b/route/content-based-router/README.md
new file mode 100644
index 0000000..ca66bc3
--- /dev/null
+++ b/route/content-based-router/README.md
@@ -0,0 +1,66 @@
+# Content-based router
+
+Three orders from three countries. A `choice` routes each by its country: the
Danish order to local delivery,
+EU orders to shipping without customs, everything else to export with a
customs declaration.
+
+## What you will see
+
+```text
+INFO ... content-based-router.camel.yaml:22 : Order ORD-1001 from DK: local
delivery from the Copenhagen warehouse
+INFO ... content-based-router.camel.yaml:28 : Order ORD-1002 from DE: EU
shipping, no customs
+INFO ... content-based-router.camel.yaml:32 : Order ORD-1003 from US: export,
customs declaration needed
+```
+
+## Install Camel CLI
+
+<!-- see installation instructions in ../../install.adoc -->
+
+## Run it
+
+```shell
+camel run *
+```
+
+The three orders in `orders/` are read once each (`noop: true` leaves the
files in place), so the run
+can be repeated.
+
+## How it works
+
+- The `file` consumer reads the three orders from `orders/` in name order;
`unmarshal` with `json` parses each,
+ so `${body[country]}` reads a field.
+- `choice` tests the country: `== 'DK'` first, then `in 'DE,SE,NL,FR'`, the
simple language's list test, and
+ `otherwise` takes the rest. The first matching `when` wins.
+- Each branch only logs here; in a real shop each `to:` a different route or
system.
+
+## Build it step by step
+
+1. A `file` route on `orders` that unmarshals each order and logs
`${body[orderId]}` and `${body[country]}`.
+2. Add a `choice` with one `when` for `DK` and an `otherwise`, each logging a
different line.
+3. Add a second `when` for the EU countries with `in 'DE,SE,NL,FR'`.
+4. Add a fourth order file for a Swedish customer and see it take the EU
branch.
+
+## Try changing
+
+- Route on the order value instead: `${body[lines].size()} > 2` for big orders.
+- Replace the logs with `to: direct:...` routes, one per branch, as
`filter-and-multicast` does.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/)
YAML DSL,
+`test/content-based-router.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/content-based-router.citrus.it.yaml
+```
+
+The test starts the route and verifies that each of the three orders is logged
from its branch.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/route/content-based-router/application.properties
b/route/content-based-router/application.properties
new file mode 100644
index 0000000..13a8339
--- /dev/null
+++ b/route/content-based-router/application.properties
@@ -0,0 +1,16 @@
+# 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.
diff --git a/route/content-based-router/content-based-router.camel.yaml
b/route/content-based-router/content-based-router.camel.yaml
new file mode 100644
index 0000000..017afee
--- /dev/null
+++ b/route/content-based-router/content-based-router.camel.yaml
@@ -0,0 +1,33 @@
+# Three orders from three countries. A choice routes each by its country:
Danish orders go to the
+# local warehouse, EU orders ship without customs, everything else is an
export with a customs
+# declaration. Each branch logs what it did.
+- route:
+ id: content-based-router
+ from:
+ uri: file
+ parameters:
+ directoryName: orders
+ noop: true
+ sortBy: "file:name"
+ steps:
+ - unmarshal:
+ json:
+ library: Jackson
+ - choice:
+ when:
+ - expression:
+ simple:
+ expression: "${body[country]} == 'DK'"
+ steps:
+ - log:
+ message: "Order ${body[orderId]} from ${body[country]}:
local delivery from the Copenhagen warehouse"
+ - expression:
+ simple:
+ expression: "${body[country]} in 'DE,SE,NL,FR'"
+ steps:
+ - log:
+ message: "Order ${body[orderId]} from ${body[country]}:
EU shipping, no customs"
+ otherwise:
+ steps:
+ - log:
+ message: "Order ${body[orderId]} from ${body[country]}:
export, customs declaration needed"
diff --git a/route/content-based-router/metadata.json
b/route/content-based-router/metadata.json
new file mode 100644
index 0000000..5aba724
--- /dev/null
+++ b/route/content-based-router/metadata.json
@@ -0,0 +1,28 @@
+{
+ "title": "Content-based router",
+ "description": "Three orders from three countries are read from the orders
directory and a choice routes each by its country: the Danish order to local
delivery, the German order to EU shipping without customs, the US order to
export with a customs declaration; each branch logs what it did.",
+ "level": "route",
+ "teaches": {
+ "components": [
+ "file",
+ "log"
+ ],
+ "eips": [
+ "choice",
+ "unmarshal"
+ ],
+ "languages": [
+ "simple"
+ ],
+ "dataformats": [
+ "json"
+ ]
+ },
+ "tags": [
+ "shop",
+ "eip",
+ "choice",
+ "routing"
+ ],
+ "bundled": false
+}
diff --git a/route/content-based-router/orders/order-1001.json
b/route/content-based-router/orders/order-1001.json
new file mode 100644
index 0000000..3eb5f03
--- /dev/null
+++ b/route/content-based-router/orders/order-1001.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1001", "customer": "C-482", "country": "DK", "status": "paid",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 2, "price": 19.95}, {"sku":
"CAMEL-MUG", "qty": 1, "price": 9.50}]}
diff --git a/route/content-based-router/orders/order-1002.json
b/route/content-based-router/orders/order-1002.json
new file mode 100644
index 0000000..bb7aa0e
--- /dev/null
+++ b/route/content-based-router/orders/order-1002.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1002", "customer": "C-207", "country": "DE", "status": "paid",
+ "lines": [{"sku": "CAMEL-MUG", "qty": 3, "price": 9.50}]}
diff --git a/route/content-based-router/orders/order-1003.json
b/route/content-based-router/orders/order-1003.json
new file mode 100644
index 0000000..9edab76
--- /dev/null
+++ b/route/content-based-router/orders/order-1003.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1003", "customer": "C-134", "country": "US", "status":
"pending",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 1, "price": 19.95}, {"sku":
"CAMEL-CAP", "qty": 1, "price": 14.00}, {"sku": "CAMEL-MUG", "qty": 2, "price":
9.50}]}
diff --git
a/route/content-based-router/test/content-based-router.citrus.it.yaml
b/route/content-based-router/test/content-based-router.citrus.it.yaml
new file mode 100644
index 0000000..508c901
--- /dev/null
+++ b/route/content-based-router/test/content-based-router.citrus.it.yaml
@@ -0,0 +1,30 @@
+name: content-based-router-test
+description: The content-based-router example logs what its README promises
+actions:
+ - camel:
+ jbang:
+ run:
+ integration:
+ name: "content-based-router"
+ file: "../content-based-router.camel.yaml"
+ systemProperties:
+ file: "../application.properties"
+ resources:
+ - "orders/order-1001.json"
+ - "orders/order-1002.json"
+ - "orders/order-1003.json"
+ - camel:
+ jbang:
+ verify:
+ integration: "content-based-router"
+ logMessage: "ORD-1001 from DK: local delivery"
+ - camel:
+ jbang:
+ verify:
+ integration: "content-based-router"
+ logMessage: "ORD-1002 from DE: EU shipping"
+ - camel:
+ jbang:
+ verify:
+ integration: "content-based-router"
+ logMessage: "ORD-1003 from US: export"
diff --git a/route/filter-and-multicast/README.md
b/route/filter-and-multicast/README.md
new file mode 100644
index 0000000..8418ed4
--- /dev/null
+++ b/route/filter-and-multicast/README.md
@@ -0,0 +1,68 @@
+# Filter and multicast
+
+Only paid orders go further, and a paid order goes to two places at once: the
warehouse to pick it and invoicing
+to bill it. The `filter` drops the unpaid order; the `multicast` sends the
same message to both routes.
+
+## What you will see
+
+```text
+INFO ... filter-and-multicast.camel.yaml:16 : Order ORD-1001 received, status
paid
+INFO ... filter-and-multicast.camel.yaml:40 : Warehouse: pick 2 line(s) for
ORD-1001
+INFO ... filter-and-multicast.camel.yaml:49 : Invoicing: bill customer C-482
for ORD-1001
+INFO ... filter-and-multicast.camel.yaml:16 : Order ORD-1002 received, status
paid
+...
+INFO ... filter-and-multicast.camel.yaml:16 : Order ORD-1003 received, status
pending
+```
+
+## Install Camel CLI
+
+<!-- see installation instructions in ../../install.adoc -->
+
+## Run it
+
+```shell
+camel run *
+```
+
+The three orders in `orders/` are read once each (`noop: true` leaves the
files in place), so the run
+can be repeated.
+
+## How it works
+
+- `filter` with `${body[status]} == 'paid'` lets paid orders into its steps;
the pending order is logged as
+ received and goes no further, which is the difference from `choice`: a
filter has no otherwise.
+- `multicast` sends a copy of the message to each `to:` in turn,
`direct:warehouse` then `direct:invoicing`.
+- The two `direct` routes are the two departments; each logs its part of the
work.
+
+## Build it step by step
+
+1. A `file` route on `orders` that unmarshals each order and logs its id and
status.
+2. Add a `filter` on the status and log inside it; the pending order
disappears from the inner log.
+3. Add `direct:warehouse` and `direct:invoicing` routes and a `multicast` to
both inside the filter.
+4. Add `parallelProcessing: true` to the multicast and see both departments
log at the same moment.
+
+## Try changing
+
+- Add a third department, `direct:analytics`, that logs the order total.
+- Use `recipientList` with a header listing the departments instead of a fixed
`multicast`.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/)
YAML DSL,
+`test/filter-and-multicast.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/filter-and-multicast.citrus.it.yaml
+```
+
+The test starts the route and verifies that the warehouse and invoicing logs
appear for the paid orders.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/route/filter-and-multicast/application.properties
b/route/filter-and-multicast/application.properties
new file mode 100644
index 0000000..13a8339
--- /dev/null
+++ b/route/filter-and-multicast/application.properties
@@ -0,0 +1,16 @@
+# 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.
diff --git a/route/filter-and-multicast/filter-and-multicast.camel.yaml
b/route/filter-and-multicast/filter-and-multicast.camel.yaml
new file mode 100644
index 0000000..1559e2b
--- /dev/null
+++ b/route/filter-and-multicast/filter-and-multicast.camel.yaml
@@ -0,0 +1,50 @@
+# Only paid orders go further, and a paid order goes to two places at once:
the warehouse to pick
+# it and invoicing to bill it. The filter drops the unpaid order, the
multicast sends the same
+# message to both.
+- route:
+ id: filter-and-multicast
+ from:
+ uri: file
+ parameters:
+ directoryName: orders
+ noop: true
+ sortBy: "file:name"
+ steps:
+ - unmarshal:
+ json:
+ library: Jackson
+ - log:
+ message: "Order ${body[orderId]} received, status ${body[status]}"
+ - filter:
+ expression:
+ simple:
+ expression: "${body[status]} == 'paid'"
+ steps:
+ - multicast:
+ steps:
+ - to:
+ uri: direct
+ parameters:
+ name: warehouse
+ - to:
+ uri: direct
+ parameters:
+ name: invoicing
+- route:
+ id: warehouse
+ from:
+ uri: direct
+ parameters:
+ name: warehouse
+ steps:
+ - log:
+ message: "Warehouse: pick ${body[lines].size()} line(s) for
${body[orderId]}"
+- route:
+ id: invoicing
+ from:
+ uri: direct
+ parameters:
+ name: invoicing
+ steps:
+ - log:
+ message: "Invoicing: bill customer ${body[customer]} for
${body[orderId]}"
diff --git a/route/filter-and-multicast/metadata.json
b/route/filter-and-multicast/metadata.json
new file mode 100644
index 0000000..148267e
--- /dev/null
+++ b/route/filter-and-multicast/metadata.json
@@ -0,0 +1,30 @@
+{
+ "title": "Filter and multicast",
+ "description": "Three orders are read from the orders directory; a filter
lets only the paid ones through and a multicast sends each paid order to both
the warehouse route and the invoicing route, which log their part; the pending
order is logged as received and goes no further.",
+ "level": "route",
+ "teaches": {
+ "components": [
+ "file",
+ "direct",
+ "log"
+ ],
+ "eips": [
+ "filter",
+ "multicast",
+ "unmarshal"
+ ],
+ "languages": [
+ "simple"
+ ],
+ "dataformats": [
+ "json"
+ ]
+ },
+ "tags": [
+ "shop",
+ "eip",
+ "filter",
+ "multicast"
+ ],
+ "bundled": false
+}
diff --git a/route/filter-and-multicast/orders/order-1001.json
b/route/filter-and-multicast/orders/order-1001.json
new file mode 100644
index 0000000..3eb5f03
--- /dev/null
+++ b/route/filter-and-multicast/orders/order-1001.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1001", "customer": "C-482", "country": "DK", "status": "paid",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 2, "price": 19.95}, {"sku":
"CAMEL-MUG", "qty": 1, "price": 9.50}]}
diff --git a/route/filter-and-multicast/orders/order-1002.json
b/route/filter-and-multicast/orders/order-1002.json
new file mode 100644
index 0000000..bb7aa0e
--- /dev/null
+++ b/route/filter-and-multicast/orders/order-1002.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1002", "customer": "C-207", "country": "DE", "status": "paid",
+ "lines": [{"sku": "CAMEL-MUG", "qty": 3, "price": 9.50}]}
diff --git a/route/filter-and-multicast/orders/order-1003.json
b/route/filter-and-multicast/orders/order-1003.json
new file mode 100644
index 0000000..9edab76
--- /dev/null
+++ b/route/filter-and-multicast/orders/order-1003.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1003", "customer": "C-134", "country": "US", "status":
"pending",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 1, "price": 19.95}, {"sku":
"CAMEL-CAP", "qty": 1, "price": 14.00}, {"sku": "CAMEL-MUG", "qty": 2, "price":
9.50}]}
diff --git
a/route/filter-and-multicast/test/filter-and-multicast.citrus.it.yaml
b/route/filter-and-multicast/test/filter-and-multicast.citrus.it.yaml
new file mode 100644
index 0000000..dae997f
--- /dev/null
+++ b/route/filter-and-multicast/test/filter-and-multicast.citrus.it.yaml
@@ -0,0 +1,30 @@
+name: filter-and-multicast-test
+description: The filter-and-multicast example logs what its README promises
+actions:
+ - camel:
+ jbang:
+ run:
+ integration:
+ name: "filter-and-multicast"
+ file: "../filter-and-multicast.camel.yaml"
+ systemProperties:
+ file: "../application.properties"
+ resources:
+ - "orders/order-1001.json"
+ - "orders/order-1002.json"
+ - "orders/order-1003.json"
+ - camel:
+ jbang:
+ verify:
+ integration: "filter-and-multicast"
+ logMessage: "Warehouse: pick 2 line(s) for ORD-1001"
+ - camel:
+ jbang:
+ verify:
+ integration: "filter-and-multicast"
+ logMessage: "Invoicing: bill customer C-207 for ORD-1002"
+ - camel:
+ jbang:
+ verify:
+ integration: "filter-and-multicast"
+ logMessage: "Order ORD-1003 received, status pending"
diff --git a/route/order-lines/README.md b/route/order-lines/README.md
new file mode 100644
index 0000000..154e401
--- /dev/null
+++ b/route/order-lines/README.md
@@ -0,0 +1,71 @@
+# Order lines
+
+An order is one message with several lines; the warehouse picks one line at a
time. The splitter turns the order
+into one message per line, and the order id travels along in a header.
+
+## What you will see
+
+```text
+INFO ... order-lines.camel.yaml:20 : Order ORD-1001 with 2 line(s)
+INFO ... order-lines.camel.yaml:27 : pick 2 x CAMEL-TSHIRT for ORD-1001
+INFO ... order-lines.camel.yaml:27 : pick 1 x CAMEL-MUG for ORD-1001
+INFO ... order-lines.camel.yaml:29 : Order ORD-1001: all 2 line(s) sent to
picking
+INFO ... order-lines.camel.yaml:20 : Order ORD-1002 with 1 line(s)
+...
+```
+
+## Install Camel CLI
+
+<!-- see installation instructions in ../../install.adoc -->
+
+## Run it
+
+```shell
+camel run *
+```
+
+The three orders in `orders/` are read once each (`noop: true` leaves the
files in place), so the run
+can be repeated.
+
+## How it works
+
+- The order is parsed with `unmarshal` and `json`, so `${body[lines]}` is a
list and `${body[lines].size()}` its
+ length.
+- `setHeader` keeps the order id before the split: headers are copied to every
split message, so each pick line
+ knows its order.
+- `split` with `${body[lines]}` runs its steps once per line with that line as
the body; `CamelSplitIndex` and
+ `CamelSplitSize` are available inside if a count is needed.
+- After the split the route continues with the original order, which logs the
confirmation.
+
+## Build it step by step
+
+1. A `file` route on `orders` that unmarshals each order and logs the number
of lines.
+2. Add `split` over `${body[lines]}` and log `${body[sku]}` inside it.
+3. Keep the order id in a header before the split and use it in the pick line.
+4. Log the confirmation after the split and notice the body is the whole order
again.
+
+## Try changing
+
+- Send each line to a `direct:pick` route instead of logging; the `aggregator`
example collects them again.
+- Split in parallel with `parallelProcessing: true` and watch the pick lines
interleave.
+
+## Integration testing
+
+The example comes with a test in the [Citrus](https://citrusframework.org/)
YAML DSL,
+`test/order-lines.citrus.it.yaml`, which the Camel CLI runs:
+
+```shell
+camel test run test/order-lines.citrus.it.yaml
+```
+
+The test starts the route and verifies the pick lines and the confirmation.
+
+## Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git a/route/order-lines/application.properties
b/route/order-lines/application.properties
new file mode 100644
index 0000000..13a8339
--- /dev/null
+++ b/route/order-lines/application.properties
@@ -0,0 +1,16 @@
+# 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.
diff --git a/route/order-lines/metadata.json b/route/order-lines/metadata.json
new file mode 100644
index 0000000..1466b46
--- /dev/null
+++ b/route/order-lines/metadata.json
@@ -0,0 +1,29 @@
+{
+ "title": "Order lines",
+ "description": "Each order read from the orders directory is split into
one message per line, the order id travels along in a header, and the log shows
the order, one pick line per line, and the parent's confirmation that all lines
went to picking.",
+ "level": "route",
+ "teaches": {
+ "components": [
+ "file",
+ "log"
+ ],
+ "eips": [
+ "split",
+ "setHeader",
+ "unmarshal"
+ ],
+ "languages": [
+ "simple"
+ ],
+ "dataformats": [
+ "json"
+ ]
+ },
+ "tags": [
+ "shop",
+ "eip",
+ "splitter",
+ "split"
+ ],
+ "bundled": false
+}
diff --git a/route/order-lines/order-lines.camel.yaml
b/route/order-lines/order-lines.camel.yaml
new file mode 100644
index 0000000..9f8c2ad
--- /dev/null
+++ b/route/order-lines/order-lines.camel.yaml
@@ -0,0 +1,30 @@
+# An order is one message with several lines; the warehouse picks one line at
a time. The splitter
+# turns the order into one message per line, and the split messages keep the
order id in a header.
+- route:
+ id: order-lines
+ from:
+ uri: file
+ parameters:
+ directoryName: orders
+ noop: true
+ sortBy: "file:name"
+ steps:
+ - unmarshal:
+ json:
+ library: Jackson
+ - setHeader:
+ name: orderId
+ expression:
+ simple:
+ expression: "${body[orderId]}"
+ - log:
+ message: "Order ${header.orderId} with ${body[lines].size()}
line(s)"
+ - split:
+ expression:
+ simple:
+ expression: "${body[lines]}"
+ steps:
+ - log:
+ message: " pick ${body[qty]} x ${body[sku]} for
${header.orderId}"
+ - log:
+ message: "Order ${header.orderId}: all ${body[lines].size()}
line(s) sent to picking"
diff --git a/route/order-lines/orders/order-1001.json
b/route/order-lines/orders/order-1001.json
new file mode 100644
index 0000000..3eb5f03
--- /dev/null
+++ b/route/order-lines/orders/order-1001.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1001", "customer": "C-482", "country": "DK", "status": "paid",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 2, "price": 19.95}, {"sku":
"CAMEL-MUG", "qty": 1, "price": 9.50}]}
diff --git a/route/order-lines/orders/order-1002.json
b/route/order-lines/orders/order-1002.json
new file mode 100644
index 0000000..bb7aa0e
--- /dev/null
+++ b/route/order-lines/orders/order-1002.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1002", "customer": "C-207", "country": "DE", "status": "paid",
+ "lines": [{"sku": "CAMEL-MUG", "qty": 3, "price": 9.50}]}
diff --git a/route/order-lines/orders/order-1003.json
b/route/order-lines/orders/order-1003.json
new file mode 100644
index 0000000..9edab76
--- /dev/null
+++ b/route/order-lines/orders/order-1003.json
@@ -0,0 +1,2 @@
+{"orderId": "ORD-1003", "customer": "C-134", "country": "US", "status":
"pending",
+ "lines": [{"sku": "CAMEL-TSHIRT", "qty": 1, "price": 19.95}, {"sku":
"CAMEL-CAP", "qty": 1, "price": 14.00}, {"sku": "CAMEL-MUG", "qty": 2, "price":
9.50}]}
diff --git a/route/order-lines/test/order-lines.citrus.it.yaml
b/route/order-lines/test/order-lines.citrus.it.yaml
new file mode 100644
index 0000000..6bbfb54
--- /dev/null
+++ b/route/order-lines/test/order-lines.citrus.it.yaml
@@ -0,0 +1,25 @@
+name: order-lines-test
+description: The order-lines example logs what its README promises
+actions:
+ - camel:
+ jbang:
+ run:
+ integration:
+ name: "order-lines"
+ file: "../order-lines.camel.yaml"
+ systemProperties:
+ file: "../application.properties"
+ resources:
+ - "orders/order-1001.json"
+ - "orders/order-1002.json"
+ - "orders/order-1003.json"
+ - camel:
+ jbang:
+ verify:
+ integration: "order-lines"
+ logMessage: "pick 2 x CAMEL-TSHIRT for ORD-1001"
+ - camel:
+ jbang:
+ verify:
+ integration: "order-lines"
+ logMessage: "Order ORD-1003: all 3 line(s) sent to picking"