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 17ba42af2df0 CAMEL-26236: camel-ignite - the existing query results
carry the key header, a PUT of a Map with a key stores it as one value, RUN
keeps the body, and no operation or no body fails with a clear message (#29078)
17ba42af2df0 is described below
commit 17ba42af2df0101be81d0884be96d2343b49c163
Author: Andrea Cosentino <[email protected]>
AuthorDate: Tue Nov 3 12:11:28 2026 +0100
CAMEL-26236: camel-ignite - the existing query results carry the key
header, a PUT of a Map with a key stores it as one value, RUN keeps the body,
and no operation or no body fails with a clear message (#29078)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
.../camel/catalog/components/ignite-cache.json | 6 +-
.../camel/catalog/components/ignite-compute.json | 4 +-
.../camel/catalog/components/ignite-idgen.json | 2 +-
.../camel/catalog/components/ignite-queue.json | 2 +-
.../camel/catalog/docs/ignite-cache-component.adoc | 6 +-
.../catalog/docs/ignite-compute-component.adoc | 3 +
.../camel/catalog/docs/ignite-idgen-component.adoc | 4 ++
.../camel/catalog/docs/ignite-queue-component.adoc | 3 +
.../camel/catalog/docs/ignite-set-component.adoc | 3 +
.../camel/component/ignite/cache/ignite-cache.json | 6 +-
.../component/ignite/compute/ignite-compute.json | 4 +-
.../camel/component/ignite/idgen/ignite-idgen.json | 2 +-
.../camel/component/ignite/queue/ignite-queue.json | 2 +-
.../src/main/docs/ignite-cache-component.adoc | 6 +-
.../src/main/docs/ignite-compute-component.adoc | 3 +
.../src/main/docs/ignite-idgen-component.adoc | 4 ++
.../src/main/docs/ignite-queue-component.adoc | 3 +
.../src/main/docs/ignite-set-component.adoc | 3 +
.../cache/IgniteCacheContinuousQueryConsumer.java | 9 +--
.../ignite/cache/IgniteCacheEndpoint.java | 17 +++--
.../ignite/cache/IgniteCacheProducer.java | 31 ++++++---
.../ignite/compute/IgniteComputeEndpoint.java | 15 +++--
.../ignite/compute/IgniteComputeProducer.java | 75 ++++++++++++++++------
.../ignite/idgen/IgniteIdGenEndpoint.java | 6 +-
.../ignite/idgen/IgniteIdGenProducer.java | 31 +++++++--
.../ignite/queue/IgniteQueueEndpoint.java | 8 +--
.../ignite/queue/IgniteQueueProducer.java | 33 ++++++++--
.../component/ignite/set/IgniteSetProducer.java | 33 ++++++++--
.../ignite/IgniteCacheContinuousQueryTest.java | 21 ++++++
.../camel/component/ignite/IgniteCacheTest.java | 68 ++++++++++++++++++++
.../camel/component/ignite/IgniteComputeTest.java | 63 ++++++++++++++++--
.../camel/component/ignite/IgniteIdGenTest.java | 44 +++++++++++++
.../camel/component/ignite/IgniteQueueTest.java | 29 +++++++++
.../camel/component/ignite/IgniteSetTest.java | 28 ++++++++
.../ignite/TestIgniteComputeResources.java | 26 ++++++++
.../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc | 25 ++++++++
36 files changed, 535 insertions(+), 93 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ignite-cache.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ignite-cache.json
index 348cb48c6c01..c229e182cc3e 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ignite-cache.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ignite-cache.json
@@ -41,9 +41,9 @@
"CamelIgniteCacheOldValue": { "index": 6, "kind": "header", "displayName":
"", "group": "common", "label": "", "required": false, "javaType": "Object",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "(producer) The old cache value to be replaced when
invoking the REPLACE operation. (consumer) This header carries the old cache
value when passed in the incoming cache event.", "constantName":
"org.apache.camel.component.ignite.IgniteConst [...]
},
"bodyTypes": {
- "consumerOut": { "carriers": [ "unknown" ], "byOption": [ { "option":
"oneExchangePerUpdate", "value": "false", "carriers": [ "list" ] }, { "option":
"fireExistingQueryResults", "value": "true", "carriers": [ "unknown" ] } ],
"description": "The new value of the cache entry that changed, with its key in
the CamelIgniteCacheKey header, the old value in CamelIgniteCacheOldValue and
the event type in CamelIgniteCacheEventType. With oneExchangePerUpdate=false a
List of the CacheEntryEven [...]
- "producerIn": { "carriers": [ "any" ], "description": "PUT and REPLACE
store the body as the value of the key in the CamelIgniteCacheKey header, and a
PUT of a Map puts all its entries; no body fails. GET and REMOVE take the key
from that header, or else from the body, where a Set is several keys. QUERY
needs an Ignite Query in the body or the CamelIgniteCacheQuery header. SIZE,
CLEAR and REBALANCE do not use the body. The operation is the operation option
or the CamelIgniteCacheOper [...]
- "producerOut": { "carriers": [ "unknown" ], "dependsOn": [
"propagateIncomingBodyIfNoReturnValue" ], "byOption": [ { "option":
"operation", "value": "PUT", "carriers": [ "unchanged", "null" ] }, { "option":
"operation", "value": "REPLACE", "carriers": [ "unchanged" ] }, { "option":
"operation", "value": "REMOVE", "carriers": [ "unchanged" ] }, { "option":
"operation", "value": "CLEAR", "carriers": [ "unchanged" ] }, { "option":
"operation", "value": "REBALANCE", "carriers": [ "unchan [...]
+ "consumerOut": { "carriers": [ "unknown" ], "byOption": [ { "option":
"oneExchangePerUpdate", "value": "false", "carriers": [ "list" ] } ],
"description": "The new value of the cache entry that changed, with its key in
the CamelIgniteCacheKey header, the old value in CamelIgniteCacheOldValue and
the event type in CamelIgniteCacheEventType. With oneExchangePerUpdate=false a
List of the CacheEntryEvents of Ignite per batch; with
fireExistingQueryResults=true the entries the initial que [...]
+ "producerIn": { "carriers": [ "any" ], "description": "PUT and REPLACE
store the body as the value of the key in the CamelIgniteCacheKey header, a Map
as well. A PUT of a Map without that header puts all its entries, unless
treatCollectionsAsCacheObjects=true; no body fails. GET and REMOVE take the key
from that header, or else from the body, where a Set is several keys. QUERY
needs an Ignite Query in the body or the CamelIgniteCacheQuery header. SIZE,
CLEAR and REBALANCE do not use [...]
+ "producerOut": { "carriers": [ "unknown" ], "dependsOn": [
"propagateIncomingBodyIfNoReturnValue" ], "byOption": [ { "option":
"operation", "value": "PUT", "carriers": [ "unchanged" ] }, { "option":
"operation", "value": "REPLACE", "carriers": [ "unchanged" ] }, { "option":
"operation", "value": "REMOVE", "carriers": [ "unchanged" ] }, { "option":
"operation", "value": "CLEAR", "carriers": [ "unchanged" ] }, { "option":
"operation", "value": "REBALANCE", "carriers": [ "unchanged" ] } [...]
},
"properties": {
"cacheName": { "index": 0, "kind": "path", "displayName": "Cache Name",
"group": "common", "label": "", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The cache name." },
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ignite-compute.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ignite-compute.json
index 6e2bedb40a51..d56fb4e453bf 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ignite-compute.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ignite-compute.json
@@ -38,8 +38,8 @@
"CamelIgniteComputeAffinityKey": { "index": 4, "kind": "header",
"displayName": "", "group": "producer", "label": "producer", "required": false,
"javaType": "Object", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "Affinity key for the AFFINITY_CALL and
AFFINITY_RUN operations.", "constantName":
"org.apache.camel.component.ignite.IgniteConstants#IGNITE_COMPUTE_AFFINITY_KEY"
}
},
"bodyTypes": {
- "producerIn": { "carriers": [ "pojo", "list" ], "dependsOn": [ "taskName"
], "description": "The job to run on the cluster, by executionType: an
IgniteCallable for CALL and AFFINITY_CALL, an IgniteRunnable for RUN and
AFFINITY_RUN, a Collection of them for CALL and RUN, an IgniteCallable,
IgniteRunnable or IgniteClosure for BROADCAST, an IgniteClosure for APPLY, and
a ComputeTask or its Class for EXECUTE. Its parameters are in the
CamelIgniteComputeParameters header. With taskName, E [...]
- "producerOut": { "carriers": [ "unknown" ], "byOption": [ { "option":
"executionType", "value": "RUN", "carriers": [ "null" ] }, { "option":
"executionType", "value": "AFFINITY_RUN", "carriers": [ "null" ] }, { "option":
"executionType", "value": "BROADCAST", "carriers": [ "list", "null" ] } ],
"description": "The result of the job. A Collection of callables, a broadcast
and an APPLY of a Collection of parameters give a Collection of the results,
unless an IgniteReducer in the CamelI [...]
+ "producerIn": { "carriers": [ "pojo", "list" ], "dependsOn": [ "taskName"
], "description": "The job to run on the cluster, by executionType: an
IgniteCallable for CALL and AFFINITY_CALL, an IgniteRunnable for RUN and
AFFINITY_RUN, a Collection of them for CALL and RUN, an IgniteCallable,
IgniteRunnable or IgniteClosure for BROADCAST, an IgniteClosure for APPLY, and
a ComputeTask or its Class for EXECUTE. Its parameters are in the
CamelIgniteComputeParameters header. With taskName, E [...]
+ "producerOut": { "carriers": [ "unknown" ], "dependsOn": [
"propagateIncomingBodyIfNoReturnValue" ], "byOption": [ { "option":
"executionType", "value": "RUN", "carriers": [ "unchanged" ] }, { "option":
"executionType", "value": "AFFINITY_RUN", "carriers": [ "unchanged" ] }, {
"option": "executionType", "value": "BROADCAST", "carriers": [ "list", "null" ]
} ], "description": "The result of the job. A Collection of callables, a
broadcast and an APPLY of a Collection of parameters give [...]
},
"properties": {
"endpointId": { "index": 0, "kind": "path", "displayName": "Endpoint Id",
"group": "producer", "label": "", "required": true, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "The endpoint ID (not
used)." },
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ignite-idgen.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ignite-idgen.json
index 432245af793d..683e251b4acf 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ignite-idgen.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ignite-idgen.json
@@ -34,7 +34,7 @@
"CamelIgniteIdGenOperation": { "index": 0, "kind": "header",
"displayName": "", "group": "producer", "label": "producer", "required": false,
"javaType": "org.apache.camel.component.ignite.idgen.IgniteIdGenOperation",
"enum": [ "ADD_AND_GET", "GET", "GET_AND_ADD", "GET_AND_INCREMENT",
"INCREMENT_AND_GET" ], "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "Allows you to dynamically change the ID
Generator operation.", "constantName": "org [...]
},
"bodyTypes": {
- "producerIn": { "carriers": [ "any" ], "byOption": [ { "option":
"operation", "value": "ADD_AND_GET", "carriers": [ "value", "text" ] }, {
"option": "operation", "value": "GET_AND_ADD", "carriers": [ "value", "text" ]
} ], "description": "ADD_AND_GET and GET_AND_ADD add the body to the sequence:
a number, or text of one; no body fails. The other operations do not use the
body, but text that is not a number still fails. The operation is the operation
option or the CamelIgniteIdGenOper [...]
+ "producerIn": { "carriers": [ "any" ], "byOption": [ { "option":
"operation", "value": "ADD_AND_GET", "carriers": [ "value", "text" ] }, {
"option": "operation", "value": "GET_AND_ADD", "carriers": [ "value", "text" ]
} ], "description": "ADD_AND_GET and GET_AND_ADD add the body to the sequence:
a number, or text of one; no body fails. The other operations do not use the
body. The operation is the operation option or the CamelIgniteIdGenOperation
header; with neither the producer fails" },
"producerOut": { "carriers": [ "value" ], "javaType": "java.lang.Long",
"description": "The value of the sequence, as a Long" }
},
"properties": {
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ignite-queue.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ignite-queue.json
index cad10bfde3ea..1756e068812f 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ignite-queue.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ignite-queue.json
@@ -37,7 +37,7 @@
"CamelIgniteQueueTimeoutMillis": { "index": 3, "kind": "header",
"displayName": "", "group": "producer", "label": "producer", "required": false,
"javaType": "Long", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "Dynamically sets the timeout in
milliseconds to use when invoking the OFFER or POLL operations.",
"constantName":
"org.apache.camel.component.ignite.IgniteConstants#IGNITE_QUEUE_TIMEOUT_MILLIS"
}
},
"bodyTypes": {
- "producerIn": { "carriers": [ "any" ], "description": "ADD, OFFER, PUT,
CONTAINS, REMOVE and RETAIN_ALL use the body as the element, and a Collection
as several elements unless treatCollectionsAsCacheObjects=true; no body fails
ADD, CONTAINS, REMOVE and RETAIN_ALL. DRAIN drains into a Collection body, or a
new List. The other operations do not use the body. The operation is the
operation option or the CamelIgniteQueueOperation header; with neither the
producer fails" },
+ "producerIn": { "carriers": [ "any" ], "description": "ADD, OFFER, PUT,
CONTAINS, REMOVE and RETAIN_ALL use the body as the element, and a Collection
as several elements unless treatCollectionsAsCacheObjects=true; no body fails
them. DRAIN drains into a Collection body, or a new List. The other operations
do not use the body. The operation is the operation option or the
CamelIgniteQueueOperation header; with neither the producer fails" },
"producerOut": { "carriers": [ "unknown" ], "dependsOn": [
"propagateIncomingBodyIfNoReturnValue" ], "byOption": [ { "option":
"operation", "value": "ADD", "carriers": [ "value" ], "javaType":
"java.lang.Boolean" }, { "option": "operation", "value": "OFFER", "carriers": [
"value" ], "javaType": "java.lang.Boolean" }, { "option": "operation", "value":
"CONTAINS", "carriers": [ "value" ], "javaType": "java.lang.Boolean" }, {
"option": "operation", "value": "REMOVE", "carriers": [ "valu [...]
},
"properties": {
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ignite-cache-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ignite-cache-component.adoc
index f25f4943ac2a..31217b1ba174 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ignite-cache-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ignite-cache-component.adoc
@@ -18,9 +18,13 @@ The Ignite Cache endpoint is one of camel-ignite endpoints
that allow you to int
This offers both a Producer (to invoke cache operations on an Ignite cache)
and a Consumer (to consume changes from a continuous query).
The cache value is the body of the message, and the cache key is in the
`CamelIgniteCacheKey` message header.
-GET and REMOVE take the key from the body when that header is not set, and a
PUT of a `Map` body puts all its entries.
+GET and REMOVE take the key from the body when that header is not set.
+A PUT of a `Map` body without that header puts all its entries; with the
header, or with `treatCollectionsAsCacheObjects=true`, the `Map` is stored as
one value.
Even if you configure a fixed operation in the endpoint URI, you can vary it
per-exchange by setting the `CamelIgniteCacheOperation` message header.
+Without either, the producer fails.
+
+With `fireExistingQueryResults=true`, the consumer first sends the entries
that the initial query finds, each with the value as the body and the key in
the `CamelIgniteCacheKey` header, like the events that follow.
// component options: START
include::partial$component-configure-options.adoc[]
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ignite-compute-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ignite-compute-component.adoc
index cadc21011e48..343e6993f2c5 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ignite-compute-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ignite-compute-component.adoc
@@ -41,6 +41,9 @@ Each operation expects the indicated types:
| AFFINITY_RUN | IgniteRunnable.
|=======================================================================
+Without a body the producer fails, except EXECUTE with the `taskName` option,
which then passes the `CamelIgniteComputeParameters` header to the task.
+RUN and AFFINITY_RUN have no result: they keep the body, or leave no body when
`propagateIncomingBodyIfNoReturnValue` is `false`.
+
== Usage
The component needs an Ignite node: xref:ignite-summary.adoc[Ignite] describes
the ways to give it one.
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ignite-idgen-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ignite-idgen-component.adoc
index 8bc0e893e125..5d4d6a052fe2 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ignite-idgen-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ignite-idgen-component.adoc
@@ -16,6 +16,10 @@
The Ignite ID Generator endpoint is one of camel-ignite endpoints that allow
you to interact with https://apacheignite.readme.io/docs/id-generator[Ignite
Atomic Sequences and ID Generators].
+`ADD_AND_GET` and `GET_AND_ADD` add the number in the body to the sequence,
and fail without a body.
+The other operations do not use the body.
+The operation is the `operation` option, or the `CamelIgniteIdGenOperation`
header; without either, the producer fails.
+
// component options: START
include::partial$component-configure-options.adoc[]
include::partial$component-endpoint-options.adoc[]
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ignite-queue-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ignite-queue-component.adoc
index 154b9027bc4f..2bdcd2352891 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ignite-queue-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ignite-queue-component.adoc
@@ -16,6 +16,9 @@
The Ignite Queue endpoint is one of camel-ignite endpoints that allow you to
interact with https://apacheignite.readme.io/docs/queue-and-set[Ignite Queue
data structures].
+`ADD`, `OFFER`, `PUT`, `CONTAINS`, `REMOVE` and `RETAIN_ALL` use the body as
the element, and fail without a body.
+The operation is the `operation` option, or the `CamelIgniteQueueOperation`
header; without either, the producer fails.
+
// component options: START
include::partial$component-configure-options.adoc[]
include::partial$component-endpoint-options.adoc[]
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ignite-set-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ignite-set-component.adoc
index d8a11ce1af09..e618e93f6b40 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ignite-set-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ignite-set-component.adoc
@@ -16,6 +16,9 @@
The Ignite Sets endpoint is one of camel-ignite endpoints that allows you to
interact with https://apacheignite.readme.io/docs/queue-and-set[Ignite Set data
structures].
+`ADD`, `CONTAINS`, `REMOVE` and `RETAIN_ALL` use the body as the element, and
fail without a body.
+The operation is the `operation` option, or the `CamelIgniteSetsOperation`
header; without either, the producer fails.
+
// component options: START
include::partial$component-configure-options.adoc[]
include::partial$component-endpoint-options.adoc[]
diff --git
a/components/camel-ignite/src/generated/resources/META-INF/org/apache/camel/component/ignite/cache/ignite-cache.json
b/components/camel-ignite/src/generated/resources/META-INF/org/apache/camel/component/ignite/cache/ignite-cache.json
index 348cb48c6c01..c229e182cc3e 100644
---
a/components/camel-ignite/src/generated/resources/META-INF/org/apache/camel/component/ignite/cache/ignite-cache.json
+++
b/components/camel-ignite/src/generated/resources/META-INF/org/apache/camel/component/ignite/cache/ignite-cache.json
@@ -41,9 +41,9 @@
"CamelIgniteCacheOldValue": { "index": 6, "kind": "header", "displayName":
"", "group": "common", "label": "", "required": false, "javaType": "Object",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "(producer) The old cache value to be replaced when
invoking the REPLACE operation. (consumer) This header carries the old cache
value when passed in the incoming cache event.", "constantName":
"org.apache.camel.component.ignite.IgniteConst [...]
},
"bodyTypes": {
- "consumerOut": { "carriers": [ "unknown" ], "byOption": [ { "option":
"oneExchangePerUpdate", "value": "false", "carriers": [ "list" ] }, { "option":
"fireExistingQueryResults", "value": "true", "carriers": [ "unknown" ] } ],
"description": "The new value of the cache entry that changed, with its key in
the CamelIgniteCacheKey header, the old value in CamelIgniteCacheOldValue and
the event type in CamelIgniteCacheEventType. With oneExchangePerUpdate=false a
List of the CacheEntryEven [...]
- "producerIn": { "carriers": [ "any" ], "description": "PUT and REPLACE
store the body as the value of the key in the CamelIgniteCacheKey header, and a
PUT of a Map puts all its entries; no body fails. GET and REMOVE take the key
from that header, or else from the body, where a Set is several keys. QUERY
needs an Ignite Query in the body or the CamelIgniteCacheQuery header. SIZE,
CLEAR and REBALANCE do not use the body. The operation is the operation option
or the CamelIgniteCacheOper [...]
- "producerOut": { "carriers": [ "unknown" ], "dependsOn": [
"propagateIncomingBodyIfNoReturnValue" ], "byOption": [ { "option":
"operation", "value": "PUT", "carriers": [ "unchanged", "null" ] }, { "option":
"operation", "value": "REPLACE", "carriers": [ "unchanged" ] }, { "option":
"operation", "value": "REMOVE", "carriers": [ "unchanged" ] }, { "option":
"operation", "value": "CLEAR", "carriers": [ "unchanged" ] }, { "option":
"operation", "value": "REBALANCE", "carriers": [ "unchan [...]
+ "consumerOut": { "carriers": [ "unknown" ], "byOption": [ { "option":
"oneExchangePerUpdate", "value": "false", "carriers": [ "list" ] } ],
"description": "The new value of the cache entry that changed, with its key in
the CamelIgniteCacheKey header, the old value in CamelIgniteCacheOldValue and
the event type in CamelIgniteCacheEventType. With oneExchangePerUpdate=false a
List of the CacheEntryEvents of Ignite per batch; with
fireExistingQueryResults=true the entries the initial que [...]
+ "producerIn": { "carriers": [ "any" ], "description": "PUT and REPLACE
store the body as the value of the key in the CamelIgniteCacheKey header, a Map
as well. A PUT of a Map without that header puts all its entries, unless
treatCollectionsAsCacheObjects=true; no body fails. GET and REMOVE take the key
from that header, or else from the body, where a Set is several keys. QUERY
needs an Ignite Query in the body or the CamelIgniteCacheQuery header. SIZE,
CLEAR and REBALANCE do not use [...]
+ "producerOut": { "carriers": [ "unknown" ], "dependsOn": [
"propagateIncomingBodyIfNoReturnValue" ], "byOption": [ { "option":
"operation", "value": "PUT", "carriers": [ "unchanged" ] }, { "option":
"operation", "value": "REPLACE", "carriers": [ "unchanged" ] }, { "option":
"operation", "value": "REMOVE", "carriers": [ "unchanged" ] }, { "option":
"operation", "value": "CLEAR", "carriers": [ "unchanged" ] }, { "option":
"operation", "value": "REBALANCE", "carriers": [ "unchanged" ] } [...]
},
"properties": {
"cacheName": { "index": 0, "kind": "path", "displayName": "Cache Name",
"group": "common", "label": "", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The cache name." },
diff --git
a/components/camel-ignite/src/generated/resources/META-INF/org/apache/camel/component/ignite/compute/ignite-compute.json
b/components/camel-ignite/src/generated/resources/META-INF/org/apache/camel/component/ignite/compute/ignite-compute.json
index 6e2bedb40a51..d56fb4e453bf 100644
---
a/components/camel-ignite/src/generated/resources/META-INF/org/apache/camel/component/ignite/compute/ignite-compute.json
+++
b/components/camel-ignite/src/generated/resources/META-INF/org/apache/camel/component/ignite/compute/ignite-compute.json
@@ -38,8 +38,8 @@
"CamelIgniteComputeAffinityKey": { "index": 4, "kind": "header",
"displayName": "", "group": "producer", "label": "producer", "required": false,
"javaType": "Object", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "Affinity key for the AFFINITY_CALL and
AFFINITY_RUN operations.", "constantName":
"org.apache.camel.component.ignite.IgniteConstants#IGNITE_COMPUTE_AFFINITY_KEY"
}
},
"bodyTypes": {
- "producerIn": { "carriers": [ "pojo", "list" ], "dependsOn": [ "taskName"
], "description": "The job to run on the cluster, by executionType: an
IgniteCallable for CALL and AFFINITY_CALL, an IgniteRunnable for RUN and
AFFINITY_RUN, a Collection of them for CALL and RUN, an IgniteCallable,
IgniteRunnable or IgniteClosure for BROADCAST, an IgniteClosure for APPLY, and
a ComputeTask or its Class for EXECUTE. Its parameters are in the
CamelIgniteComputeParameters header. With taskName, E [...]
- "producerOut": { "carriers": [ "unknown" ], "byOption": [ { "option":
"executionType", "value": "RUN", "carriers": [ "null" ] }, { "option":
"executionType", "value": "AFFINITY_RUN", "carriers": [ "null" ] }, { "option":
"executionType", "value": "BROADCAST", "carriers": [ "list", "null" ] } ],
"description": "The result of the job. A Collection of callables, a broadcast
and an APPLY of a Collection of parameters give a Collection of the results,
unless an IgniteReducer in the CamelI [...]
+ "producerIn": { "carriers": [ "pojo", "list" ], "dependsOn": [ "taskName"
], "description": "The job to run on the cluster, by executionType: an
IgniteCallable for CALL and AFFINITY_CALL, an IgniteRunnable for RUN and
AFFINITY_RUN, a Collection of them for CALL and RUN, an IgniteCallable,
IgniteRunnable or IgniteClosure for BROADCAST, an IgniteClosure for APPLY, and
a ComputeTask or its Class for EXECUTE. Its parameters are in the
CamelIgniteComputeParameters header. With taskName, E [...]
+ "producerOut": { "carriers": [ "unknown" ], "dependsOn": [
"propagateIncomingBodyIfNoReturnValue" ], "byOption": [ { "option":
"executionType", "value": "RUN", "carriers": [ "unchanged" ] }, { "option":
"executionType", "value": "AFFINITY_RUN", "carriers": [ "unchanged" ] }, {
"option": "executionType", "value": "BROADCAST", "carriers": [ "list", "null" ]
} ], "description": "The result of the job. A Collection of callables, a
broadcast and an APPLY of a Collection of parameters give [...]
},
"properties": {
"endpointId": { "index": 0, "kind": "path", "displayName": "Endpoint Id",
"group": "producer", "label": "", "required": true, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "The endpoint ID (not
used)." },
diff --git
a/components/camel-ignite/src/generated/resources/META-INF/org/apache/camel/component/ignite/idgen/ignite-idgen.json
b/components/camel-ignite/src/generated/resources/META-INF/org/apache/camel/component/ignite/idgen/ignite-idgen.json
index 432245af793d..683e251b4acf 100644
---
a/components/camel-ignite/src/generated/resources/META-INF/org/apache/camel/component/ignite/idgen/ignite-idgen.json
+++
b/components/camel-ignite/src/generated/resources/META-INF/org/apache/camel/component/ignite/idgen/ignite-idgen.json
@@ -34,7 +34,7 @@
"CamelIgniteIdGenOperation": { "index": 0, "kind": "header",
"displayName": "", "group": "producer", "label": "producer", "required": false,
"javaType": "org.apache.camel.component.ignite.idgen.IgniteIdGenOperation",
"enum": [ "ADD_AND_GET", "GET", "GET_AND_ADD", "GET_AND_INCREMENT",
"INCREMENT_AND_GET" ], "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "Allows you to dynamically change the ID
Generator operation.", "constantName": "org [...]
},
"bodyTypes": {
- "producerIn": { "carriers": [ "any" ], "byOption": [ { "option":
"operation", "value": "ADD_AND_GET", "carriers": [ "value", "text" ] }, {
"option": "operation", "value": "GET_AND_ADD", "carriers": [ "value", "text" ]
} ], "description": "ADD_AND_GET and GET_AND_ADD add the body to the sequence:
a number, or text of one; no body fails. The other operations do not use the
body, but text that is not a number still fails. The operation is the operation
option or the CamelIgniteIdGenOper [...]
+ "producerIn": { "carriers": [ "any" ], "byOption": [ { "option":
"operation", "value": "ADD_AND_GET", "carriers": [ "value", "text" ] }, {
"option": "operation", "value": "GET_AND_ADD", "carriers": [ "value", "text" ]
} ], "description": "ADD_AND_GET and GET_AND_ADD add the body to the sequence:
a number, or text of one; no body fails. The other operations do not use the
body. The operation is the operation option or the CamelIgniteIdGenOperation
header; with neither the producer fails" },
"producerOut": { "carriers": [ "value" ], "javaType": "java.lang.Long",
"description": "The value of the sequence, as a Long" }
},
"properties": {
diff --git
a/components/camel-ignite/src/generated/resources/META-INF/org/apache/camel/component/ignite/queue/ignite-queue.json
b/components/camel-ignite/src/generated/resources/META-INF/org/apache/camel/component/ignite/queue/ignite-queue.json
index cad10bfde3ea..1756e068812f 100644
---
a/components/camel-ignite/src/generated/resources/META-INF/org/apache/camel/component/ignite/queue/ignite-queue.json
+++
b/components/camel-ignite/src/generated/resources/META-INF/org/apache/camel/component/ignite/queue/ignite-queue.json
@@ -37,7 +37,7 @@
"CamelIgniteQueueTimeoutMillis": { "index": 3, "kind": "header",
"displayName": "", "group": "producer", "label": "producer", "required": false,
"javaType": "Long", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "Dynamically sets the timeout in
milliseconds to use when invoking the OFFER or POLL operations.",
"constantName":
"org.apache.camel.component.ignite.IgniteConstants#IGNITE_QUEUE_TIMEOUT_MILLIS"
}
},
"bodyTypes": {
- "producerIn": { "carriers": [ "any" ], "description": "ADD, OFFER, PUT,
CONTAINS, REMOVE and RETAIN_ALL use the body as the element, and a Collection
as several elements unless treatCollectionsAsCacheObjects=true; no body fails
ADD, CONTAINS, REMOVE and RETAIN_ALL. DRAIN drains into a Collection body, or a
new List. The other operations do not use the body. The operation is the
operation option or the CamelIgniteQueueOperation header; with neither the
producer fails" },
+ "producerIn": { "carriers": [ "any" ], "description": "ADD, OFFER, PUT,
CONTAINS, REMOVE and RETAIN_ALL use the body as the element, and a Collection
as several elements unless treatCollectionsAsCacheObjects=true; no body fails
them. DRAIN drains into a Collection body, or a new List. The other operations
do not use the body. The operation is the operation option or the
CamelIgniteQueueOperation header; with neither the producer fails" },
"producerOut": { "carriers": [ "unknown" ], "dependsOn": [
"propagateIncomingBodyIfNoReturnValue" ], "byOption": [ { "option":
"operation", "value": "ADD", "carriers": [ "value" ], "javaType":
"java.lang.Boolean" }, { "option": "operation", "value": "OFFER", "carriers": [
"value" ], "javaType": "java.lang.Boolean" }, { "option": "operation", "value":
"CONTAINS", "carriers": [ "value" ], "javaType": "java.lang.Boolean" }, {
"option": "operation", "value": "REMOVE", "carriers": [ "valu [...]
},
"properties": {
diff --git a/components/camel-ignite/src/main/docs/ignite-cache-component.adoc
b/components/camel-ignite/src/main/docs/ignite-cache-component.adoc
index f25f4943ac2a..31217b1ba174 100644
--- a/components/camel-ignite/src/main/docs/ignite-cache-component.adoc
+++ b/components/camel-ignite/src/main/docs/ignite-cache-component.adoc
@@ -18,9 +18,13 @@ The Ignite Cache endpoint is one of camel-ignite endpoints
that allow you to int
This offers both a Producer (to invoke cache operations on an Ignite cache)
and a Consumer (to consume changes from a continuous query).
The cache value is the body of the message, and the cache key is in the
`CamelIgniteCacheKey` message header.
-GET and REMOVE take the key from the body when that header is not set, and a
PUT of a `Map` body puts all its entries.
+GET and REMOVE take the key from the body when that header is not set.
+A PUT of a `Map` body without that header puts all its entries; with the
header, or with `treatCollectionsAsCacheObjects=true`, the `Map` is stored as
one value.
Even if you configure a fixed operation in the endpoint URI, you can vary it
per-exchange by setting the `CamelIgniteCacheOperation` message header.
+Without either, the producer fails.
+
+With `fireExistingQueryResults=true`, the consumer first sends the entries
that the initial query finds, each with the value as the body and the key in
the `CamelIgniteCacheKey` header, like the events that follow.
// component options: START
include::partial$component-configure-options.adoc[]
diff --git
a/components/camel-ignite/src/main/docs/ignite-compute-component.adoc
b/components/camel-ignite/src/main/docs/ignite-compute-component.adoc
index cadc21011e48..343e6993f2c5 100644
--- a/components/camel-ignite/src/main/docs/ignite-compute-component.adoc
+++ b/components/camel-ignite/src/main/docs/ignite-compute-component.adoc
@@ -41,6 +41,9 @@ Each operation expects the indicated types:
| AFFINITY_RUN | IgniteRunnable.
|=======================================================================
+Without a body the producer fails, except EXECUTE with the `taskName` option,
which then passes the `CamelIgniteComputeParameters` header to the task.
+RUN and AFFINITY_RUN have no result: they keep the body, or leave no body when
`propagateIncomingBodyIfNoReturnValue` is `false`.
+
== Usage
The component needs an Ignite node: xref:ignite-summary.adoc[Ignite] describes
the ways to give it one.
diff --git a/components/camel-ignite/src/main/docs/ignite-idgen-component.adoc
b/components/camel-ignite/src/main/docs/ignite-idgen-component.adoc
index 8bc0e893e125..5d4d6a052fe2 100644
--- a/components/camel-ignite/src/main/docs/ignite-idgen-component.adoc
+++ b/components/camel-ignite/src/main/docs/ignite-idgen-component.adoc
@@ -16,6 +16,10 @@
The Ignite ID Generator endpoint is one of camel-ignite endpoints that allow
you to interact with https://apacheignite.readme.io/docs/id-generator[Ignite
Atomic Sequences and ID Generators].
+`ADD_AND_GET` and `GET_AND_ADD` add the number in the body to the sequence,
and fail without a body.
+The other operations do not use the body.
+The operation is the `operation` option, or the `CamelIgniteIdGenOperation`
header; without either, the producer fails.
+
// component options: START
include::partial$component-configure-options.adoc[]
include::partial$component-endpoint-options.adoc[]
diff --git a/components/camel-ignite/src/main/docs/ignite-queue-component.adoc
b/components/camel-ignite/src/main/docs/ignite-queue-component.adoc
index 154b9027bc4f..2bdcd2352891 100644
--- a/components/camel-ignite/src/main/docs/ignite-queue-component.adoc
+++ b/components/camel-ignite/src/main/docs/ignite-queue-component.adoc
@@ -16,6 +16,9 @@
The Ignite Queue endpoint is one of camel-ignite endpoints that allow you to
interact with https://apacheignite.readme.io/docs/queue-and-set[Ignite Queue
data structures].
+`ADD`, `OFFER`, `PUT`, `CONTAINS`, `REMOVE` and `RETAIN_ALL` use the body as
the element, and fail without a body.
+The operation is the `operation` option, or the `CamelIgniteQueueOperation`
header; without either, the producer fails.
+
// component options: START
include::partial$component-configure-options.adoc[]
include::partial$component-endpoint-options.adoc[]
diff --git a/components/camel-ignite/src/main/docs/ignite-set-component.adoc
b/components/camel-ignite/src/main/docs/ignite-set-component.adoc
index d8a11ce1af09..e618e93f6b40 100644
--- a/components/camel-ignite/src/main/docs/ignite-set-component.adoc
+++ b/components/camel-ignite/src/main/docs/ignite-set-component.adoc
@@ -16,6 +16,9 @@
The Ignite Sets endpoint is one of camel-ignite endpoints that allows you to
interact with https://apacheignite.readme.io/docs/queue-and-set[Ignite Set data
structures].
+`ADD`, `CONTAINS`, `REMOVE` and `RETAIN_ALL` use the body as the element, and
fail without a body.
+The operation is the `operation` option, or the `CamelIgniteSetsOperation`
header; without either, the producer fails.
+
// component options: START
include::partial$component-configure-options.adoc[]
include::partial$component-endpoint-options.adoc[]
diff --git
a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/cache/IgniteCacheContinuousQueryConsumer.java
b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/cache/IgniteCacheContinuousQueryConsumer.java
index 04bc639e2d56..41f978f5e6a6 100644
---
a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/cache/IgniteCacheContinuousQueryConsumer.java
+++
b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/cache/IgniteCacheContinuousQueryConsumer.java
@@ -21,7 +21,6 @@ import javax.cache.event.CacheEntryEvent;
import javax.cache.event.CacheEntryListenerException;
import javax.cache.event.CacheEntryUpdatedListener;
-import org.apache.camel.AsyncCallback;
import org.apache.camel.Exchange;
import org.apache.camel.ExchangePattern;
import org.apache.camel.Message;
@@ -75,14 +74,10 @@ public class IgniteCacheContinuousQueryConsumer extends
DefaultConsumer {
LOG.info("Processing existing cache results for cache name = {}.",
endpoint.getCacheName());
for (Entry<Object, Object> entry : cursor) {
+ // the value as the body and the key as a header, like the events
of the continuous query
Exchange exchange = createExchange(entry.getValue());
exchange.getIn().setHeader(IgniteConstants.IGNITE_CACHE_KEY,
entry.getKey());
- getAsyncProcessor().process(createExchange(entry), new
AsyncCallback() {
- @Override
- public void done(boolean doneSync) {
- // do nothing
- }
- });
+ getAsyncProcessor().process(exchange, EmptyAsyncCallback.get());
}
}
diff --git
a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/cache/IgniteCacheEndpoint.java
b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/cache/IgniteCacheEndpoint.java
index 2bff9c98b559..09484ccca4c5 100644
---
a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/cache/IgniteCacheEndpoint.java
+++
b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/cache/IgniteCacheEndpoint.java
@@ -50,19 +50,19 @@ import static
org.apache.camel.component.ignite.IgniteConstants.SCHEME_CACHE;
@BodyTypes(consumerOut = @BodyType(value = Carrier.UNKNOWN,
byOption = {
@BodyType.When(option =
"oneExchangePerUpdate", value = "false",
- carriers =
Carrier.LIST),
- @BodyType.When(option =
"fireExistingQueryResults", value = "true",
- carriers =
Carrier.UNKNOWN) },
+ carriers =
Carrier.LIST) },
description = "The new value of the cache
entry that changed, with its key in the"
+ " CamelIgniteCacheKey
header, the old value in CamelIgniteCacheOldValue and"
+ " the event type in
CamelIgniteCacheEventType. With oneExchangePerUpdate=false"
+ " a List of the
CacheEntryEvents of Ignite per batch; with"
+ "
fireExistingQueryResults=true the entries the initial query finds come"
- + " first, each as a JCache
Cache.Entry"),
+ + " first, each with its
value as the body and its key in the"
+ + " CamelIgniteCacheKey
header"),
producerIn = @BodyType(value = Carrier.ANY,
description = "PUT and REPLACE store the
body as the value of the key in the"
- + " CamelIgniteCacheKey
header, and a PUT of a Map puts all its entries; no"
- + " body fails. GET and REMOVE
take the key from that header, or else from the"
+ + " CamelIgniteCacheKey
header, a Map as well. A PUT of a Map without that"
+ + " header puts all its
entries, unless treatCollectionsAsCacheObjects=true;"
+ + " no body fails. GET and
REMOVE take the key from that header, or else from the"
+ " body, where a Set is
several keys. QUERY needs an Ignite Query in the body"
+ " or the
CamelIgniteCacheQuery header. SIZE, CLEAR and REBALANCE do not use"
+ " the body. The operation is
the operation option or the"
@@ -71,7 +71,7 @@ import static
org.apache.camel.component.ignite.IgniteConstants.SCHEME_CACHE;
dependsOn =
"propagateIncomingBodyIfNoReturnValue",
byOption = {
@BodyType.When(option =
"operation", value = "PUT",
- carriers = {
Carrier.UNCHANGED, Carrier.NULL }),
+ carriers =
Carrier.UNCHANGED),
@BodyType.When(option =
"operation", value = "REPLACE",
carriers =
Carrier.UNCHANGED),
@BodyType.When(option =
"operation", value = "REMOVE",
@@ -87,8 +87,7 @@ import static
org.apache.camel.component.ignite.IgniteConstants.SCHEME_CACHE;
description = "GET gives the cached value,
or null when the key is not cached, and a Map"
+ " of the keys and their
values for a Set of keys. QUERY gives an Iterator of"
+ " the entries found, closed
when the exchange completes. SIZE gives the"
- + " number of entries. The
others leave the body, but a PUT of a Map leaves no"
- + " body"))
+ + " number of entries. The
others leave the body"))
public class IgniteCacheEndpoint extends AbstractIgniteEndpoint {
@UriPath
diff --git
a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/cache/IgniteCacheProducer.java
b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/cache/IgniteCacheProducer.java
index afdab7542a08..abfaf30d726f 100644
---
a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/cache/IgniteCacheProducer.java
+++
b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/cache/IgniteCacheProducer.java
@@ -51,11 +51,12 @@ public class IgniteCacheProducer extends
DefaultAsyncProducer {
@Override
public boolean process(Exchange exchange, AsyncCallback callback) {
+ IgniteCacheOperation operation = cacheOperationFor(exchange);
Message in = exchange.getIn();
Message out = exchange.getOut();
MessageHelper.copyHeaders(exchange.getIn(), out, true);
- switch (cacheOperationFor(exchange)) {
+ switch (operation) {
case GET:
doGet(in, out);
@@ -110,19 +111,23 @@ public class IgniteCacheProducer extends
DefaultAsyncProducer {
@SuppressWarnings("unchecked")
private void doPut(Message in, Message out) {
- Map<Object, Object> map = in.getBody(Map.class);
+ Object cacheKey = in.getHeader(IgniteConstants.IGNITE_CACHE_KEY);
- if (map != null) {
- cache.putAll(map);
- return;
+ // a Map is put as its entries only without a key, and when
collections are not cache objects:
+ // otherwise it is stored as one value, like any other body
+ if (cacheKey == null && !endpoint.isTreatCollectionsAsCacheObjects()) {
+ Map<Object, Object> map = in.getBody(Map.class);
+ if (map != null) {
+ cache.putAll(map);
+ IgniteHelper.maybePropagateIncomingBody(endpoint, in, out);
+ return;
+ }
}
- Object cacheKey = in.getHeader(IgniteConstants.IGNITE_CACHE_KEY);
-
if (cacheKey == null) {
throw new RuntimeCamelException(
"Cache PUT operation requires the cache key in the
CamelIgniteCacheKey header, "
- + "or a payload of type Map.");
+ + "or a payload of type Map when
treatCollectionsAsCacheObjects is false.");
}
cache.put(cacheKey, in.getBody());
@@ -227,8 +232,14 @@ public class IgniteCacheProducer extends
DefaultAsyncProducer {
}
private IgniteCacheOperation cacheOperationFor(Exchange exchange) {
- return
exchange.getIn().getHeader(IgniteConstants.IGNITE_CACHE_OPERATION,
endpoint.getOperation(),
- IgniteCacheOperation.class);
+ IgniteCacheOperation operation =
exchange.getIn().getHeader(IgniteConstants.IGNITE_CACHE_OPERATION,
+ endpoint.getOperation(), IgniteCacheOperation.class);
+ if (operation == null) {
+ throw new IllegalArgumentException(
+ "No operation specified. Set the operation via the
operation option of the endpoint or the header "
+ +
IgniteConstants.IGNITE_CACHE_OPERATION);
+ }
+ return operation;
}
}
diff --git
a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/compute/IgniteComputeEndpoint.java
b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/compute/IgniteComputeEndpoint.java
index 136adea0c895..528d4b759602 100644
---
a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/compute/IgniteComputeEndpoint.java
+++
b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/compute/IgniteComputeEndpoint.java
@@ -52,18 +52,23 @@ import static
org.apache.camel.component.ignite.IgniteConstants.SCHEME_COMPUTE;
+ " IgniteClosure for
BROADCAST, an IgniteClosure for APPLY, and a ComputeTask or"
+ " its Class for EXECUTE. Its
parameters are in the CamelIgniteComputeParameters"
+ " header. With taskName,
EXECUTE runs that task with the body as its"
- + " argument. Text or no body
fails"),
+ + " argument, or with that
header when there is no body. Otherwise text or no"
+ + " body fails"),
producerOut = @BodyType(value = Carrier.UNKNOWN,
+ dependsOn =
"propagateIncomingBodyIfNoReturnValue",
byOption = {
- @BodyType.When(option =
"executionType", value = "RUN", carriers = Carrier.NULL),
+ @BodyType.When(option =
"executionType", value = "RUN",
+ carriers =
Carrier.UNCHANGED),
@BodyType.When(option =
"executionType", value = "AFFINITY_RUN",
- carriers =
Carrier.NULL),
+ carriers =
Carrier.UNCHANGED),
@BodyType.When(option =
"executionType", value = "BROADCAST",
carriers = {
Carrier.LIST, Carrier.NULL }) },
description = "The result of the job. A
Collection of callables, a broadcast and an APPLY"
+ " of a Collection of
parameters give a Collection of the results, unless an"
- + " IgniteReducer in the
CamelIgniteComputeReducer header reduces them. RUN,"
- + " AFFINITY_RUN and a
broadcast IgniteRunnable leave no body"))
+ + " IgniteReducer in the
CamelIgniteComputeReducer header reduces them. RUN and"
+ + " AFFINITY_RUN have no
result and keep the body, or leave no body with"
+ + "
propagateIncomingBodyIfNoReturnValue=false. A broadcast IgniteRunnable"
+ + " leaves no body"))
public class IgniteComputeEndpoint extends AbstractIgniteEndpoint {
@UriPath
diff --git
a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/compute/IgniteComputeProducer.java
b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/compute/IgniteComputeProducer.java
index 7cd196b9d23c..db7f73ebfde5 100644
---
a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/compute/IgniteComputeProducer.java
+++
b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/compute/IgniteComputeProducer.java
@@ -21,6 +21,7 @@ import java.util.Collection;
import org.apache.camel.AsyncCallback;
import org.apache.camel.Exchange;
+import org.apache.camel.InvalidPayloadException;
import org.apache.camel.Message;
import org.apache.camel.NoTypeConversionAvailableException;
import org.apache.camel.RuntimeCamelException;
@@ -54,7 +55,8 @@ public class IgniteComputeProducer extends
DefaultAsyncProducer {
IgniteCompute compute = endpoint.createIgniteCompute().withAsync();
try {
- switch (executionTypeFor(exchange)) {
+ IgniteComputeExecutionType executionType =
executionTypeFor(exchange);
+ switch (executionType) {
case CALL:
doCall(exchange, compute);
@@ -91,7 +93,11 @@ public class IgniteComputeProducer extends
DefaultAsyncProducer {
return false;
}
- compute.future().listen(IgniteInCamelClosure.create(exchange,
callback));
+ // RUN and AFFINITY_RUN have no result, so they keep the incoming
body unless told otherwise
+ boolean propagateIncomingBody = (executionType ==
IgniteComputeExecutionType.RUN
+ || executionType ==
IgniteComputeExecutionType.AFFINITY_RUN)
+ && endpoint.isPropagateIncomingBodyIfNoReturnValue();
+ compute.future().listen(IgniteInCamelClosure.create(exchange,
callback, propagateIncomingBody));
return false;
} catch (Exception e) {
@@ -102,8 +108,9 @@ public class IgniteComputeProducer extends
DefaultAsyncProducer {
}
@SuppressWarnings({ "unchecked", "rawtypes" })
- private void doCall(final Exchange exchange, IgniteCompute compute) throws
NoTypeConversionAvailableException {
- Object job = exchange.getIn().getBody();
+ private void doCall(final Exchange exchange, IgniteCompute compute)
+ throws NoTypeConversionAvailableException, InvalidPayloadException
{
+ Object job = mandatoryJob(exchange, IgniteComputeExecutionType.CALL,
"an IgniteCallable, or a Collection of them");
IgniteReducer<Object, Object> reducer
=
exchange.getIn().getHeader(IgniteConstants.IGNITE_COMPUTE_REDUCER,
IgniteReducer.class);
@@ -131,8 +138,9 @@ public class IgniteComputeProducer extends
DefaultAsyncProducer {
}
@SuppressWarnings("unchecked")
- private void doBroadcast(final Exchange exchange, IgniteCompute compute) {
- Object job = exchange.getIn().getBody();
+ private void doBroadcast(final Exchange exchange, IgniteCompute compute)
throws InvalidPayloadException {
+ Object job = mandatoryJob(exchange,
IgniteComputeExecutionType.BROADCAST,
+ "an IgniteCallable, an IgniteRunnable or an IgniteClosure");
if (IgniteCallable.class.isAssignableFrom(job.getClass())) {
compute.broadcast((IgniteCallable<?>) job);
@@ -150,20 +158,25 @@ public class IgniteComputeProducer extends
DefaultAsyncProducer {
}
@SuppressWarnings("unchecked")
- private void doExecute(final Exchange exchange, IgniteCompute compute) {
+ private void doExecute(final Exchange exchange, IgniteCompute compute)
throws InvalidPayloadException {
Object job = exchange.getIn().getBody();
Object params =
exchange.getIn().getHeader(IgniteConstants.IGNITE_COMPUTE_PARAMS);
if (job instanceof Class &&
ComputeTask.class.isAssignableFrom((Class<?>) job)) {
Class<? extends ComputeTask<Object, Object>> task = (Class<?
extends ComputeTask<Object, Object>>) job;
compute.execute(task, params);
- } else if (ComputeTask.class.isAssignableFrom(job.getClass())) {
+ } else if (job instanceof ComputeTask) {
compute.execute((ComputeTask<Object, Object>) job, params);
} else if (endpoint.getTaskName() != null) {
- if (exchange.getIn().getBody() != null) {
- params = exchange.getIn().getBody();
+ // the body is the argument of the task; without a body the
CamelIgniteComputeParameters header is
+ if (job != null) {
+ params = job;
}
compute.execute(endpoint.getTaskName(), params);
+ } else if (job == null) {
+ throw new InvalidPayloadException(
+ exchange, Object.class, exchange.getIn(),
+ "the EXECUTE executionType needs a ComputeTask, or its
Class, in the message body, or the taskName option");
} else {
throw new RuntimeCamelException(
String.format("Ignite Compute endpoint with EXECUTE
executionType is only "
@@ -173,8 +186,9 @@ public class IgniteComputeProducer extends
DefaultAsyncProducer {
}
}
- private void doRun(final Exchange exchange, IgniteCompute compute) throws
NoTypeConversionAvailableException {
- Object job = exchange.getIn().getBody();
+ private void doRun(final Exchange exchange, IgniteCompute compute)
+ throws NoTypeConversionAvailableException, InvalidPayloadException
{
+ Object job = mandatoryJob(exchange, IgniteComputeExecutionType.RUN,
"an IgniteRunnable, or a Collection of them");
if (Collection.class.isAssignableFrom(job.getClass())) {
Collection<?> col = (Collection<?>) job;
@@ -196,7 +210,8 @@ public class IgniteComputeProducer extends
DefaultAsyncProducer {
}
@SuppressWarnings("unchecked")
- private <T, R1, R2> void doApply(final Exchange exchange, IgniteCompute
compute) {
+ private <T, R1, R2> void doApply(final Exchange exchange, IgniteCompute
compute) throws InvalidPayloadException {
+ Object body = mandatoryJob(exchange, IgniteComputeExecutionType.APPLY,
"an IgniteClosure");
IgniteClosure<T, R1> job =
exchange.getIn().getBody(IgniteClosure.class);
T params = (T)
exchange.getIn().getHeader(IgniteConstants.IGNITE_COMPUTE_PARAMS);
@@ -204,7 +219,7 @@ public class IgniteComputeProducer extends
DefaultAsyncProducer {
throw new RuntimeCamelException(
String.format("Ignite Compute endpoint with APPLY
executionType is only "
+ "supported for IgniteClosure payloads with
parameters. The payload type was: %s.",
- exchange.getIn().getBody().getClass().getName()));
+ body.getClass().getName()));
}
IgniteReducer<R1, R2> reducer =
exchange.getIn().getHeader(IgniteConstants.IGNITE_COMPUTE_REDUCER,
IgniteReducer.class);
@@ -222,7 +237,8 @@ public class IgniteComputeProducer extends
DefaultAsyncProducer {
}
@SuppressWarnings("unchecked")
- private void doAffinityCall(final Exchange exchange, IgniteCompute
compute) {
+ private void doAffinityCall(final Exchange exchange, IgniteCompute
compute) throws InvalidPayloadException {
+ Object body = mandatoryJob(exchange,
IgniteComputeExecutionType.AFFINITY_CALL, "an IgniteCallable");
IgniteCallable<Object> job =
exchange.getIn().getBody(IgniteCallable.class);
String affinityCache =
exchange.getIn().getHeader(IgniteConstants.IGNITE_COMPUTE_AFFINITY_CACHE_NAME,
String.class);
Object affinityKey =
exchange.getIn().getHeader(IgniteConstants.IGNITE_COMPUTE_AFFINITY_KEY,
Object.class);
@@ -232,13 +248,14 @@ public class IgniteComputeProducer extends
DefaultAsyncProducer {
String.format(
"Ignite Compute endpoint with AFFINITY_CALL
executionType is only "
+ "supported for IgniteCallable payloads,
along with an affinity cache and key. The payload type was: %s.",
- exchange.getIn().getBody().getClass().getName()));
+ body.getClass().getName()));
}
compute.affinityCall(affinityCache, affinityKey, job);
}
- private void doAffinityRun(final Exchange exchange, IgniteCompute compute)
{
+ private void doAffinityRun(final Exchange exchange, IgniteCompute compute)
throws InvalidPayloadException {
+ Object body = mandatoryJob(exchange,
IgniteComputeExecutionType.AFFINITY_RUN, "an IgniteRunnable");
IgniteRunnable job = exchange.getIn().getBody(IgniteRunnable.class);
String affinityCache =
exchange.getIn().getHeader(IgniteConstants.IGNITE_COMPUTE_AFFINITY_CACHE_NAME,
String.class);
Object affinityKey =
exchange.getIn().getHeader(IgniteConstants.IGNITE_COMPUTE_AFFINITY_KEY,
Object.class);
@@ -248,12 +265,27 @@ public class IgniteComputeProducer extends
DefaultAsyncProducer {
String.format(
"Ignite Compute endpoint with AFFINITY_RUN
executionType is only "
+ "supported for IgniteRunnable payloads,
along with an affinity cache and key. The payload type was: %s.",
- exchange.getIn().getBody().getClass().getName()));
+ body.getClass().getName()));
}
compute.affinityRun(affinityCache, affinityKey, job);
}
+ /**
+ * The job in the body, or an {@link InvalidPayloadException} that says
what the execution type needs when there is
+ * no body.
+ */
+ private static Object mandatoryJob(Exchange exchange,
IgniteComputeExecutionType executionType, String job)
+ throws InvalidPayloadException {
+ Object body = exchange.getIn().getBody();
+ if (body == null) {
+ throw new InvalidPayloadException(
+ exchange, Object.class, exchange.getIn(),
+ "the " + executionType + " executionType needs " + job + "
in the message body");
+ }
+ return body;
+ }
+
private IgniteComputeExecutionType executionTypeFor(Exchange exchange) {
return
exchange.getIn().getHeader(IgniteConstants.IGNITE_COMPUTE_EXECUTION_TYPE,
endpoint.getExecutionType(),
IgniteComputeExecutionType.class);
@@ -264,11 +296,13 @@ public class IgniteComputeProducer extends
DefaultAsyncProducer {
private Exchange exchange;
private AsyncCallback callback;
+ private boolean propagateIncomingBody;
- private static IgniteInCamelClosure create(Exchange exchange,
AsyncCallback callback) {
+ private static IgniteInCamelClosure create(Exchange exchange,
AsyncCallback callback, boolean propagateIncomingBody) {
IgniteInCamelClosure answer = new IgniteInCamelClosure();
answer.exchange = exchange;
answer.callback = callback;
+ answer.propagateIncomingBody = propagateIncomingBody;
return answer;
}
@@ -288,7 +322,8 @@ public class IgniteComputeProducer extends
DefaultAsyncProducer {
return;
}
- exchange.getOut().setBody(result);
+ // a job without a result keeps the incoming body when
propagateIncomingBodyIfNoReturnValue is true
+ out.setBody(propagateIncomingBody ? in.getBody() : result);
callback.done(false);
}
}
diff --git
a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/idgen/IgniteIdGenEndpoint.java
b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/idgen/IgniteIdGenEndpoint.java
index 0e739c296af6..efc0dca2a144 100644
---
a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/idgen/IgniteIdGenEndpoint.java
+++
b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/idgen/IgniteIdGenEndpoint.java
@@ -53,9 +53,9 @@ import static
org.apache.camel.component.ignite.IgniteConstants.SCHEME_IDGEN;
@BodyType.When(option = "operation",
value = "GET_AND_ADD",
carriers = {
Carrier.VALUE, Carrier.TEXT }) },
description = "ADD_AND_GET and GET_AND_ADD
add the body to the sequence: a number, or text"
- + " of one; no body fails. The
other operations do not use the body, but text"
- + " that is not a number still
fails. The operation is the operation option or"
- + " the
CamelIgniteIdGenOperation header"),
+ + " of one; no body fails. The
other operations do not use the body. The"
+ + " operation is the operation
option or the CamelIgniteIdGenOperation header;"
+ + " with neither the producer
fails"),
producerOut = @BodyType(value = Carrier.VALUE, javaType =
"java.lang.Long",
description = "The value of the sequence,
as a Long"))
public class IgniteIdGenEndpoint extends AbstractIgniteEndpoint {
diff --git
a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/idgen/IgniteIdGenProducer.java
b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/idgen/IgniteIdGenProducer.java
index 32a4f40edde2..d0141db84f82 100644
---
a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/idgen/IgniteIdGenProducer.java
+++
b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/idgen/IgniteIdGenProducer.java
@@ -18,6 +18,7 @@ package org.apache.camel.component.ignite.idgen;
import org.apache.camel.AsyncCallback;
import org.apache.camel.Exchange;
+import org.apache.camel.InvalidPayloadException;
import org.apache.camel.Message;
import org.apache.camel.component.ignite.IgniteConstants;
import org.apache.camel.support.DefaultAsyncProducer;
@@ -41,12 +42,26 @@ public class IgniteIdGenProducer extends
DefaultAsyncProducer {
@Override
public boolean process(Exchange exchange, AsyncCallback callback) {
Message in = exchange.getIn();
+ IgniteIdGenOperation operation = idGenOperationFor(exchange);
+
+ // only the operations that add to the sequence use the body
+ long id = 0;
+ if (operation == IgniteIdGenOperation.ADD_AND_GET || operation ==
IgniteIdGenOperation.GET_AND_ADD) {
+ Long number = in.getBody(Long.class);
+ if (number == null) {
+ exchange.setException(new InvalidPayloadException(
+ exchange, Long.class, in,
+ "the " + operation + " operation needs the number to
add in the message body"));
+ callback.done(true);
+ return true;
+ }
+ id = number;
+ }
+
Message out = exchange.getOut();
MessageHelper.copyHeaders(in, out, true);
- Long id = in.getBody(Long.class);
-
- switch (idGenOperationFor(exchange)) {
+ switch (operation) {
case ADD_AND_GET:
out.setBody(atomicSeq.addAndGet(id));
@@ -79,8 +94,14 @@ public class IgniteIdGenProducer extends
DefaultAsyncProducer {
}
private IgniteIdGenOperation idGenOperationFor(Exchange exchange) {
- return
exchange.getIn().getHeader(IgniteConstants.IGNITE_IDGEN_OPERATION,
endpoint.getOperation(),
- IgniteIdGenOperation.class);
+ IgniteIdGenOperation operation =
exchange.getIn().getHeader(IgniteConstants.IGNITE_IDGEN_OPERATION,
+ endpoint.getOperation(), IgniteIdGenOperation.class);
+ if (operation == null) {
+ throw new IllegalArgumentException(
+ "No operation specified. Set the operation via the
operation option of the endpoint or the header "
+ +
IgniteConstants.IGNITE_IDGEN_OPERATION);
+ }
+ return operation;
}
}
diff --git
a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/queue/IgniteQueueEndpoint.java
b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/queue/IgniteQueueEndpoint.java
index 3a896246cba9..0b4d9c51b8f1 100644
---
a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/queue/IgniteQueueEndpoint.java
+++
b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/queue/IgniteQueueEndpoint.java
@@ -50,10 +50,10 @@ import static
org.apache.camel.component.ignite.IgniteConstants.SCHEME_QUEUE;
@BodyTypes(producerIn = @BodyType(value = Carrier.ANY,
description = "ADD, OFFER, PUT, CONTAINS,
REMOVE and RETAIN_ALL use the body as the"
+ " element, and a Collection
as several elements unless"
- + "
treatCollectionsAsCacheObjects=true; no body fails ADD, CONTAINS, REMOVE"
- + " and RETAIN_ALL. DRAIN
drains into a Collection body, or a new List. The"
- + " other operations do not
use the body. The operation is the operation option"
- + " or the
CamelIgniteQueueOperation header; with neither the producer fails"),
+ + "
treatCollectionsAsCacheObjects=true; no body fails them. DRAIN drains into"
+ + " a Collection body, or a
new List. The other operations do not use the body."
+ + " The operation is the
operation option or the CamelIgniteQueueOperation"
+ + " header; with neither the
producer fails"),
producerOut = @BodyType(value = Carrier.UNKNOWN,
dependsOn =
"propagateIncomingBodyIfNoReturnValue",
byOption = {
diff --git
a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/queue/IgniteQueueProducer.java
b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/queue/IgniteQueueProducer.java
index 8b647e8f9950..f797099b1d2b 100644
---
a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/queue/IgniteQueueProducer.java
+++
b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/queue/IgniteQueueProducer.java
@@ -19,11 +19,14 @@ package org.apache.camel.component.ignite.queue;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.EnumSet;
import java.util.Iterator;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.apache.camel.AsyncCallback;
import org.apache.camel.Exchange;
+import org.apache.camel.InvalidPayloadException;
import org.apache.camel.Message;
import org.apache.camel.component.ignite.IgniteConstants;
import org.apache.camel.support.DefaultAsyncProducer;
@@ -32,6 +35,13 @@ import org.apache.ignite.IgniteQueue;
public class IgniteQueueProducer extends DefaultAsyncProducer {
+ /**
+ * The operations that use the body as the element (or the elements) to
add, find or remove.
+ */
+ private static final Set<IgniteQueueOperation> ELEMENT_OPERATIONS =
EnumSet.of(IgniteQueueOperation.ADD,
+ IgniteQueueOperation.CONTAINS, IgniteQueueOperation.REMOVE,
IgniteQueueOperation.RETAIN_ALL,
+ IgniteQueueOperation.OFFER, IgniteQueueOperation.PUT);
+
private IgniteQueueEndpoint endpoint;
private IgniteQueue<Object> queue;
@@ -45,13 +55,22 @@ public class IgniteQueueProducer extends
DefaultAsyncProducer {
@SuppressWarnings("unchecked")
public boolean process(Exchange exchange, AsyncCallback callback) {
Message in = exchange.getIn();
+ IgniteQueueOperation operation = queueOperationFor(exchange);
+
+ Object body = in.getBody();
+ if (body == null && ELEMENT_OPERATIONS.contains(operation)) {
+ exchange.setException(new InvalidPayloadException(
+ exchange, Object.class, in, "the " + operation + "
operation needs the element in the message body"));
+ callback.done(true);
+ return true;
+ }
+
Message out = exchange.getOut();
MessageHelper.copyHeaders(exchange.getIn(), out, true);
- Object body = in.getBody();
Long millis;
- switch (queueOperationFor(exchange)) {
+ switch (operation) {
case ADD:
if (Collection.class.isAssignableFrom(body.getClass()) &&
!endpoint.isTreatCollectionsAsCacheObjects()) {
@@ -165,8 +184,14 @@ public class IgniteQueueProducer extends
DefaultAsyncProducer {
}
private IgniteQueueOperation queueOperationFor(Exchange exchange) {
- return
exchange.getIn().getHeader(IgniteConstants.IGNITE_QUEUE_OPERATION,
endpoint.getOperation(),
- IgniteQueueOperation.class);
+ IgniteQueueOperation operation =
exchange.getIn().getHeader(IgniteConstants.IGNITE_QUEUE_OPERATION,
+ endpoint.getOperation(), IgniteQueueOperation.class);
+ if (operation == null) {
+ throw new IllegalArgumentException(
+ "No operation specified. Set the operation via the
operation option of the endpoint or the header "
+ +
IgniteConstants.IGNITE_QUEUE_OPERATION);
+ }
+ return operation;
}
}
diff --git
a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/set/IgniteSetProducer.java
b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/set/IgniteSetProducer.java
index e54ee847299c..ba55614c1ac5 100644
---
a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/set/IgniteSetProducer.java
+++
b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/set/IgniteSetProducer.java
@@ -18,10 +18,13 @@ package org.apache.camel.component.ignite.set;
import java.util.Collection;
import java.util.Collections;
+import java.util.EnumSet;
import java.util.Iterator;
+import java.util.Set;
import org.apache.camel.AsyncCallback;
import org.apache.camel.Exchange;
+import org.apache.camel.InvalidPayloadException;
import org.apache.camel.Message;
import org.apache.camel.component.ignite.IgniteConstants;
import org.apache.camel.support.DefaultAsyncProducer;
@@ -33,6 +36,12 @@ import org.apache.ignite.IgniteSet;
*/
public class IgniteSetProducer extends DefaultAsyncProducer {
+ /**
+ * The operations that use the body as the element (or the elements) to
add, find or remove.
+ */
+ private static final Set<IgniteSetOperation> ELEMENT_OPERATIONS =
EnumSet.of(IgniteSetOperation.ADD,
+ IgniteSetOperation.CONTAINS, IgniteSetOperation.REMOVE,
IgniteSetOperation.RETAIN_ALL);
+
private IgniteSetEndpoint endpoint;
private IgniteSet<Object> set;
@@ -46,12 +55,20 @@ public class IgniteSetProducer extends DefaultAsyncProducer
{
@SuppressWarnings("unchecked")
public boolean process(Exchange exchange, AsyncCallback callback) {
Message in = exchange.getIn();
- Message out = exchange.getOut();
- MessageHelper.copyHeaders(exchange.getIn(), out, true);
+ IgniteSetOperation operation = setOperationFor(exchange);
Object body = in.getBody();
+ if (body == null && ELEMENT_OPERATIONS.contains(operation)) {
+ exchange.setException(new InvalidPayloadException(
+ exchange, Object.class, in, "the " + operation + "
operation needs the element in the message body"));
+ callback.done(true);
+ return true;
+ }
- switch (setOperationFor(exchange)) {
+ Message out = exchange.getOut();
+ MessageHelper.copyHeaders(exchange.getIn(), out, true);
+
+ switch (operation) {
case ADD:
if (Collection.class.isAssignableFrom(body.getClass()) &&
!endpoint.isTreatCollectionsAsCacheObjects()) {
@@ -115,8 +132,14 @@ public class IgniteSetProducer extends
DefaultAsyncProducer {
}
private IgniteSetOperation setOperationFor(Exchange exchange) {
- return
exchange.getIn().getHeader(IgniteConstants.IGNITE_SETS_OPERATION,
endpoint.getOperation(),
- IgniteSetOperation.class);
+ IgniteSetOperation operation =
exchange.getIn().getHeader(IgniteConstants.IGNITE_SETS_OPERATION,
+ endpoint.getOperation(), IgniteSetOperation.class);
+ if (operation == null) {
+ throw new IllegalArgumentException(
+ "No operation specified. Set the operation via the
operation option of the endpoint or the header "
+ +
IgniteConstants.IGNITE_SETS_OPERATION);
+ }
+ return operation;
}
}
diff --git
a/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteCacheContinuousQueryTest.java
b/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteCacheContinuousQueryTest.java
index c6dc244743e0..8db2e3ca8be1 100644
---
a/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteCacheContinuousQueryTest.java
+++
b/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteCacheContinuousQueryTest.java
@@ -122,6 +122,27 @@ public class IgniteCacheContinuousQueryTest extends
AbstractIgniteTest implement
MockEndpoint.assertIsSatisfied(context);
}
+ @Test
+ void testContinuousQueryFireExistingEntriesSendsTheValueWithTheKey()
throws Exception {
+ getMockEndpoint("mock:test2").expectedMessageCount(50);
+
+ Map<Integer, Person> persons = createPersons(1, 100);
+ IgniteCache<Integer, Person> cache =
ignite().getOrCreateCache("testcontinuous1");
+ cache.putAll(persons);
+
+
context.getRouteController().startRoute("continuousQuery.fireExistingEntries");
+
+ MockEndpoint.assertIsSatisfied(context);
+
+ // the existing entries arrive like the events: the value as the body,
and the key in a header
+ for (Exchange exchange : getMockEndpoint("mock:test2").getExchanges())
{
+ Integer key =
exchange.getIn().getHeader(IgniteConstants.IGNITE_CACHE_KEY, Integer.class);
+ Assertions.assertThat(key).isNotNull().isGreaterThan(50);
+
Assertions.assertThat(exchange.getIn().getBody()).isEqualTo(persons.get(key));
+
Assertions.assertThat(exchange.getIn().getHeader(IgniteConstants.IGNITE_CACHE_NAME)).isEqualTo("testcontinuous1");
+ }
+ }
+
@Test
public void
testContinuousQueryFireExistingEntriesWithQueryAndRemoteFilter() throws
Exception {
getMockEndpoint("mock:test3").expectedMessageCount(50);
diff --git
a/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteCacheTest.java
b/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteCacheTest.java
index b075138e8f32..be86315c66a9 100644
---
a/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteCacheTest.java
+++
b/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteCacheTest.java
@@ -16,6 +16,7 @@
*/
package org.apache.camel.component.ignite;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -25,6 +26,8 @@ import javax.cache.Cache.Entry;
import com.google.common.collect.ImmutableMap;
import org.apache.camel.CamelException;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.RuntimeCamelException;
import org.apache.camel.component.ignite.cache.IgniteCacheComponent;
import org.apache.camel.component.ignite.cache.IgniteCacheOperation;
import org.apache.camel.util.ObjectHelper;
@@ -258,6 +261,71 @@ public class IgniteCacheTest extends AbstractIgniteTest {
Assertions.assertThat(result).isNull();
}
+ @Test
+ void testPutMapWithKeyStoresTheMapAsOneValue() {
+ Map<String, String> map = new HashMap<>();
+ map.put("abcd", "1234");
+ map.put("efgh", "5678");
+
+ Object result = template.requestBodyAndHeader("ignite-cache:" +
resourceUid + "?operation=PUT", map,
+ IgniteConstants.IGNITE_CACHE_KEY, "orders");
+
+
Assertions.assertThat(ignite().cache(resourceUid).size(CachePeekMode.ALL)).isEqualTo(1);
+
Assertions.assertThat(ignite().cache(resourceUid).get("orders")).isEqualTo(map);
+ Assertions.assertThat(result).isEqualTo(map);
+ }
+
+ @Test
+ void testPutMapTreatCollectionsAsCacheObjectsStoresTheMapAsOneValue() {
+ Map<String, String> map = new HashMap<>();
+ map.put("abcd", "1234");
+ map.put("efgh", "5678");
+
+ template.requestBodyAndHeader("ignite-cache:" + resourceUid +
"?operation=PUT&treatCollectionsAsCacheObjects=true",
+ map, IgniteConstants.IGNITE_CACHE_KEY, "orders");
+
+
Assertions.assertThat(ignite().cache(resourceUid).size(CachePeekMode.ALL)).isEqualTo(1);
+
Assertions.assertThat(ignite().cache(resourceUid).get("orders")).isEqualTo(map);
+
+ // without a key there is no entry to store the Map in
+ Assertions
+ .assertThatThrownBy(() -> template.requestBody(
+ "ignite-cache:" + resourceUid +
"?operation=PUT&treatCollectionsAsCacheObjects=true", map))
+ .isInstanceOf(CamelExecutionException.class)
+ .cause().isInstanceOf(RuntimeCamelException.class)
+ .hasMessageContaining(IgniteConstants.IGNITE_CACHE_KEY);
+
Assertions.assertThat(ignite().cache(resourceUid).size(CachePeekMode.ALL)).isEqualTo(1);
+ }
+
+ @Test
+ void testPutMapEntriesPropagatesTheBody() {
+ Map<String, String> map = new HashMap<>();
+ map.put("abcd", "1234");
+ map.put("efgh", "5678");
+
+ Object result = template.requestBody("ignite-cache:" + resourceUid +
"?operation=PUT", map);
+
+
Assertions.assertThat(ignite().cache(resourceUid).size(CachePeekMode.ALL)).isEqualTo(2);
+ Assertions.assertThat(result).isEqualTo(map);
+
+ result = template.requestBody(
+ "ignite-cache:" + resourceUid +
"?operation=PUT&propagateIncomingBodyIfNoReturnValue=false", map);
+
+
Assertions.assertThat(ignite().cache(resourceUid).size(CachePeekMode.ALL)).isEqualTo(2);
+ Assertions.assertThat(result).isNull();
+ }
+
+ @Test
+ void testNoOperationFails() {
+ Assertions
+ .assertThatThrownBy(() ->
template.requestBodyAndHeader("ignite-cache:" + resourceUid, "1234",
+ IgniteConstants.IGNITE_CACHE_KEY, "abcd"))
+ .isInstanceOf(CamelExecutionException.class)
+ .cause().isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("operation option")
+ .hasMessageContaining(IgniteConstants.IGNITE_CACHE_OPERATION);
+ }
+
@AfterEach
public void deleteCaches() {
IgniteCache<?, ?> cache = ignite().cache(resourceUid);
diff --git
a/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteComputeTest.java
b/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteComputeTest.java
index b1a2694566a2..c17a31dafd77 100644
---
a/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteComputeTest.java
+++
b/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteComputeTest.java
@@ -26,8 +26,11 @@ import java.util.concurrent.TimeUnit;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.InvalidPayloadException;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.component.ignite.compute.IgniteComputeComponent;
+import org.apache.camel.component.ignite.compute.IgniteComputeExecutionType;
import org.apache.camel.util.ObjectHelper;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCluster;
@@ -103,21 +106,71 @@ public class IgniteComputeTest extends AbstractIgniteTest
{
public void testRun() {
TestIgniteComputeResources.COUNTER.set(0);
- // Single Runnable.
+ // Single Runnable: there is no result, so the body is kept.
Object result = template.requestBody("ignite-compute:" + resourceUid +
"?executionType=RUN",
TestIgniteComputeResources.TEST_RUNNABLE_COUNTER,
Object.class);
- Assertions.assertThat(result).isNull();
+
Assertions.assertThat(result).isSameAs(TestIgniteComputeResources.TEST_RUNNABLE_COUNTER);
Assertions.assertThat(TestIgniteComputeResources.COUNTER.get()).isEqualTo(1);
// Multiple Runnables.
Object[] runnables = new Object[5];
Arrays.fill(runnables,
TestIgniteComputeResources.TEST_RUNNABLE_COUNTER);
- result = template.requestBody("ignite-compute:" + resourceUid +
"?executionType=RUN", Lists.newArrayList(runnables),
- Collection.class);
- Assertions.assertThat(result).isNull();
+ List<Object> jobs = Lists.newArrayList(runnables);
+ result = template.requestBody("ignite-compute:" + resourceUid +
"?executionType=RUN", jobs, Collection.class);
+ Assertions.assertThat(result).isEqualTo(jobs);
Assertions.assertThat(TestIgniteComputeResources.COUNTER.get()).isEqualTo(6);
}
+ @Test
+ void testRunWithoutPropagateIncomingBodyLeavesNoBody() {
+ TestIgniteComputeResources.COUNTER.set(0);
+
+ Object result = template.requestBody(
+ "ignite-compute:" + resourceUid +
"?executionType=RUN&propagateIncomingBodyIfNoReturnValue=false",
+ TestIgniteComputeResources.TEST_RUNNABLE_COUNTER,
Object.class);
+ Assertions.assertThat(result).isNull();
+
Assertions.assertThat(TestIgniteComputeResources.COUNTER.get()).isEqualTo(1);
+ }
+
+ @Test
+ void testAffinityRunKeepsTheBody() {
+ TestIgniteComputeResources.COUNTER.set(0);
+ ignite().getOrCreateCache(resourceUid);
+
+ Map<String, Object> headers =
Map.of(IgniteConstants.IGNITE_COMPUTE_AFFINITY_CACHE_NAME, resourceUid,
+ IgniteConstants.IGNITE_COMPUTE_AFFINITY_KEY, "key");
+ Object result = template.requestBodyAndHeaders("ignite-compute:" +
resourceUid + "?executionType=AFFINITY_RUN",
+ TestIgniteComputeResources.TEST_RUNNABLE_COUNTER, headers,
Object.class);
+
Assertions.assertThat(result).isSameAs(TestIgniteComputeResources.TEST_RUNNABLE_COUNTER);
+
Assertions.assertThat(TestIgniteComputeResources.COUNTER.get()).isEqualTo(1);
+ }
+
+ @Test
+ void testNoBodyFails() {
+ for (IgniteComputeExecutionType executionType :
IgniteComputeExecutionType.values()) {
+ Assertions
+ .assertThatThrownBy(() -> template.requestBody(
+ "ignite-compute:" + resourceUid +
"?executionType=" + executionType, (Object) null))
+ .as(executionType.name())
+ .isInstanceOf(CamelExecutionException.class)
+ .cause().isInstanceOf(InvalidPayloadException.class)
+ .hasMessageContaining("the " + executionType + "
executionType needs");
+ }
+ }
+
+ @Test
+ void testExecuteTaskNameWithoutBodyTakesTheParametersHeader() {
+ String uri = "ignite-compute:" + resourceUid +
"?executionType=EXECUTE&taskName="
+ + TestIgniteComputeResources.EchoTask.class.getName();
+
+ String result = template.requestBodyAndHeader(uri, null,
IgniteConstants.IGNITE_COMPUTE_PARAMS, "Camel", String.class);
+ Assertions.assertThat(result).isEqualTo("echo Camel");
+
+ // a body is the argument of the task
+ result = template.requestBodyAndHeader(uri, "body",
IgniteConstants.IGNITE_COMPUTE_PARAMS, "Camel", String.class);
+ Assertions.assertThat(result).isEqualTo("echo body");
+ }
+
@Test
@SuppressWarnings("unchecked")
public void testBroadcast() {
diff --git
a/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteIdGenTest.java
b/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteIdGenTest.java
index 1cb5db601f57..21e4a71b2812 100644
---
a/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteIdGenTest.java
+++
b/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteIdGenTest.java
@@ -16,6 +16,10 @@
*/
package org.apache.camel.component.ignite;
+import java.util.List;
+
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.InvalidPayloadException;
import org.apache.camel.component.ignite.idgen.IgniteIdGenComponent;
import org.apache.camel.component.ignite.idgen.IgniteIdGenEndpoint;
import org.apache.camel.component.ignite.idgen.IgniteIdGenOperation;
@@ -109,6 +113,46 @@ public class IgniteIdGenTest extends AbstractIgniteTest {
Assertions.assertThat(endpoint.getBatchSize()).isEqualTo(100);
}
+ @Test
+ void testOperationsThatDoNotAddIgnoreTheBody() {
+ Assertions.assertThat(template.requestBody("ignite-idgen:" +
resourceUid + "?initialValue=0&operation=GET",
+ "not a number", Long.class)).isZero();
+ Assertions.assertThat(template.requestBody(
+ "ignite-idgen:" + resourceUid +
"?initialValue=0&operation=GET_AND_INCREMENT", "not a number", Long.class))
+ .isZero();
+ Assertions.assertThat(template.requestBody(
+ "ignite-idgen:" + resourceUid +
"?initialValue=0&operation=INCREMENT_AND_GET", "not a number", Long.class))
+ .isEqualTo(2);
+ }
+
+ @Test
+ void testAddWithoutBodyFails() {
+ for (IgniteIdGenOperation operation :
List.of(IgniteIdGenOperation.ADD_AND_GET, IgniteIdGenOperation.GET_AND_ADD)) {
+ Assertions
+ .assertThatThrownBy(() -> template.requestBody(
+ "ignite-idgen:" + resourceUid +
"?initialValue=0&operation=" + operation, (Object) null))
+ .isInstanceOf(CamelExecutionException.class)
+ .cause().isInstanceOf(InvalidPayloadException.class)
+ .hasMessageContaining("the " + operation + " operation
needs the number to add");
+ }
+
+ // the sequence is unchanged
+ Assertions.assertThat(
+ template.requestBody("ignite-idgen:" + resourceUid +
"?initialValue=0&operation=GET", null, Long.class))
+ .isZero();
+ }
+
+ @Test
+ void testNoOperationFails() {
+ Assertions
+ .assertThatThrownBy(
+ () -> template.requestBody("ignite-idgen:" +
resourceUid + "?initialValue=0", (Object) null))
+ .isInstanceOf(CamelExecutionException.class)
+ .cause().isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("operation option")
+ .hasMessageContaining(IgniteConstants.IGNITE_IDGEN_OPERATION);
+ }
+
@AfterEach
public void deleteSets() {
IgniteAtomicSequence seq = ignite().atomicSequence(resourceUid, 0,
false);
diff --git
a/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteQueueTest.java
b/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteQueueTest.java
index e166b2d69491..fda1bd47ee8b 100644
---
a/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteQueueTest.java
+++
b/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteQueueTest.java
@@ -28,6 +28,8 @@ import com.google.common.base.Stopwatch;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.InvalidPayloadException;
import org.apache.camel.component.ignite.queue.IgniteQueueComponent;
import org.apache.camel.component.ignite.queue.IgniteQueueEndpoint;
import org.apache.camel.component.ignite.queue.IgniteQueueOperation;
@@ -275,6 +277,33 @@ public class IgniteQueueTest extends AbstractIgniteTest {
}
+ @Test
+ void testOperationsWithAnElementFailWithoutBody() {
+ for (IgniteQueueOperation operation :
List.of(IgniteQueueOperation.ADD, IgniteQueueOperation.CONTAINS,
+ IgniteQueueOperation.REMOVE, IgniteQueueOperation.RETAIN_ALL,
IgniteQueueOperation.OFFER,
+ IgniteQueueOperation.PUT)) {
+ Assertions
+ .assertThatThrownBy(() -> template.requestBody(
+ "ignite-queue:" + resourceUid + "?operation=" +
operation, (Object) null))
+ .as(operation.name())
+ .isInstanceOf(CamelExecutionException.class)
+ .cause().isInstanceOf(InvalidPayloadException.class)
+ .hasMessageContaining("the " + operation + " operation
needs the element");
+ }
+
+ Assertions.assertThat(ignite().queue(resourceUid, 0, new
CollectionConfiguration())).isEmpty();
+ }
+
+ @Test
+ void testNoOperationFails() {
+ Assertions
+ .assertThatThrownBy(() -> template.requestBody("ignite-queue:"
+ resourceUid, "hello"))
+ .isInstanceOf(CamelExecutionException.class)
+ .cause().isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("operation option")
+ .hasMessageContaining(IgniteConstants.IGNITE_QUEUE_OPERATION);
+ }
+
@AfterEach
public void deleteQueue() {
ignite().queue(resourceUid, 0, null).close();
diff --git
a/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteSetTest.java
b/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteSetTest.java
index 71005de3b981..0ba8dacbc038 100644
---
a/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteSetTest.java
+++
b/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/IgniteSetTest.java
@@ -23,6 +23,8 @@ import java.util.Set;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.InvalidPayloadException;
import org.apache.camel.component.ignite.set.IgniteSetComponent;
import org.apache.camel.component.ignite.set.IgniteSetEndpoint;
import org.apache.camel.component.ignite.set.IgniteSetOperation;
@@ -174,6 +176,32 @@ public class IgniteSetTest extends AbstractIgniteTest {
Assertions.assertThat(igniteEndpoint.getConfiguration()).isEqualTo(configuration);
}
+ @Test
+ void testOperationsWithAnElementFailWithoutBody() {
+ for (IgniteSetOperation operation : List.of(IgniteSetOperation.ADD,
IgniteSetOperation.CONTAINS,
+ IgniteSetOperation.REMOVE, IgniteSetOperation.RETAIN_ALL)) {
+ Assertions
+ .assertThatThrownBy(() -> template.requestBody(
+ "ignite-set:" + resourceUid + "?operation=" +
operation, (Object) null))
+ .as(operation.name())
+ .isInstanceOf(CamelExecutionException.class)
+ .cause().isInstanceOf(InvalidPayloadException.class)
+ .hasMessageContaining("the " + operation + " operation
needs the element");
+ }
+
+ Assertions.assertThat(ignite().set(resourceUid, new
CollectionConfiguration())).isEmpty();
+ }
+
+ @Test
+ void testNoOperationFails() {
+ Assertions
+ .assertThatThrownBy(() -> template.requestBody("ignite-set:" +
resourceUid, "hello"))
+ .isInstanceOf(CamelExecutionException.class)
+ .cause().isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("operation option")
+ .hasMessageContaining(IgniteConstants.IGNITE_SETS_OPERATION);
+ }
+
@AfterEach
public void deleteSet() {
ignite().set(resourceUid, null).close();
diff --git
a/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/TestIgniteComputeResources.java
b/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/TestIgniteComputeResources.java
index dfb7da743884..b2bef6a722c7 100644
---
a/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/TestIgniteComputeResources.java
+++
b/components/camel-ignite/src/test/java/org/apache/camel/component/ignite/TestIgniteComputeResources.java
@@ -27,6 +27,7 @@ import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import org.apache.ignite.IgniteException;
import org.apache.ignite.compute.ComputeJob;
+import org.apache.ignite.compute.ComputeJobAdapter;
import org.apache.ignite.compute.ComputeJobResult;
import org.apache.ignite.compute.ComputeTask;
import org.apache.ignite.compute.ComputeTaskSplitAdapter;
@@ -146,4 +147,29 @@ public final class TestIgniteComputeResources {
private TestIgniteComputeResources() {
}
+
+ /**
+ * A task with one job, which gives back its argument after "echo ".
Ignite deploys it by its class name, which the
+ * taskName option of the endpoint gives.
+ */
+ public static class EchoTask extends ComputeTaskSplitAdapter<Object,
String> {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected Collection<? extends ComputeJob> split(int gridSize, Object
arg) throws IgniteException {
+ return Collections.singleton(new ComputeJobAdapter(arg) {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Object execute() throws IgniteException {
+ return "echo " + argument(0);
+ }
+ });
+ }
+
+ @Override
+ public String reduce(List<ComputeJobResult> results) throws
IgniteException {
+ return results.get(0).getData();
+ }
+ }
}
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 7e73cbe50c42..fcde13086ce7 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
@@ -4942,6 +4942,31 @@ conversion error. Previously it gave an empty SOAP body.
A reply body that is an
The `spring-ws` producer now sends a `File` body, the file of a `file` or
`ftp` consumer, and an `InputStream` body
(also when stream caching is off) as XML. Previously these failed with an
`InvalidPayloadException`.
+=== camel-ignite - cache PUT of a Map, the existing query results, RUN bodies
and missing operations
+
+With `fireExistingQueryResults=true`, the `ignite-cache` consumer now sends
each entry that the initial query finds
+with the value as the body and the key in the `CamelIgniteCacheKey` header,
like the events that follow. Before, the
+body was the `javax.cache.Cache.Entry` and the key header was not set.
+
+A PUT of a `Map` body on `ignite-cache` with the `CamelIgniteCacheKey` header
now stores the `Map` as the value of that
+key. Before, the header was ignored and all the entries of the `Map` were put.
The same holds with
+`treatCollectionsAsCacheObjects=true`, where a PUT of a `Map` without the
header now fails, as there is no key to store
+it under. A PUT of a `Map` without the header still puts all its entries, and
now keeps the body when
+`propagateIncomingBodyIfNoReturnValue` is `true` (the default). Before, the
body was `null` after such a PUT.
+
+The `RUN` and `AFFINITY_RUN` execution types of `ignite-compute` have no
result, and now keep the body (the job) when
+`propagateIncomingBodyIfNoReturnValue` is `true` (the default). Before, the
body was `null`. Set
+`propagateIncomingBodyIfNoReturnValue=false` to keep the previous behaviour.
+
+The `ignite-cache`, `ignite-idgen`, `ignite-queue` and `ignite-set` producers
now fail with an
+`IllegalArgumentException` that names the `operation` option and the operation
header when neither sets the operation.
+A missing body now fails with an `InvalidPayloadException` that names what the
operation needs: the job for
+`ignite-compute` (except `EXECUTE` with the `taskName` option, which now runs
the task with the
+`CamelIgniteComputeParameters` header), the number to add for `ADD_AND_GET`
and `GET_AND_ADD` of `ignite-idgen`, and
+the element for `ADD`, `CONTAINS`, `REMOVE` and `RETAIN_ALL` of `ignite-queue`
and `ignite-set` and for `OFFER` and
+`PUT` of `ignite-queue`. Before, these failed with a `NullPointerException`.
The `GET`, `GET_AND_INCREMENT` and
+`INCREMENT_AND_GET` operations of `ignite-idgen` no longer fail on a body that
is not a number, as they do not use it.
+
=== camel-couchbase - the document id, the operation option and the bodies of
CCB_PUT
The `couchbase` producer now uses the `key` option as the document id when the
message has no `CamelCouchbaseId`