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 105afa453098 CAMEL-24961: Catalog body types for spring-redis,
couchbase, fhir, solr, ssh, slack and telegram (#28309)
105afa453098 is described below
commit 105afa4530988df4143b26906e1bbc4ecd7fb60b
Author: Claus Ibsen <[email protected]>
AuthorDate: Sat Oct 24 10:02:33 2026 +0200
CAMEL-24961: Catalog body types for spring-redis, couchbase, fhir, solr,
ssh, slack and telegram (#28309)
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
---
.../apache/camel/catalog/components/couchbase.json | 5 +
.../org/apache/camel/catalog/components/fhir.json | 5 +
.../org/apache/camel/catalog/components/slack.json | 5 +
.../org/apache/camel/catalog/components/solr.json | 4 +
.../camel/catalog/components/spring-redis.json | 5 +
.../org/apache/camel/catalog/components/ssh.json | 5 +
.../apache/camel/catalog/components/telegram.json | 5 +
.../camel/catalog/docs/couchbase-component.adoc | 16 ++-
.../apache/camel/catalog/docs/fhir-component.adoc | 8 ++
.../apache/camel/catalog/docs/slack-component.adoc | 10 +-
.../apache/camel/catalog/docs/solr-component.adoc | 12 +-
.../camel/catalog/docs/spring-redis-component.adoc | 34 ++---
.../apache/camel/catalog/docs/ssh-component.adoc | 4 +
.../camel/catalog/docs/telegram-component.adoc | 15 ++-
.../camel/component/couchbase/couchbase.json | 5 +
.../src/main/docs/couchbase-component.adoc | 16 ++-
.../component/couchbase/CouchbaseEndpoint.java | 28 ++++
.../org/apache/camel/component/fhir/fhir.json | 5 +
.../src/main/docs/fhir-component.adoc | 8 ++
.../apache/camel/component/fhir/FhirEndpoint.java | 27 ++++
.../org/apache/camel/component/slack/slack.json | 5 +
.../camel-slack/src/main/docs/slack-component.adoc | 10 +-
.../camel/component/slack/SlackEndpoint.java | 14 ++
.../org/apache/camel/component/solr/solr.json | 4 +
.../camel-solr/src/main/docs/solr-component.adoc | 12 +-
.../apache/camel/component/solr/SolrEndpoint.java | 17 +++
.../apache/camel/component/redis/spring-redis.json | 5 +
.../src/main/docs/spring-redis-component.adoc | 34 ++---
.../camel/component/redis/RedisEndpoint.java | 85 ++++++++++++
.../org/apache/camel/component/ssh/ssh.json | 5 +
.../camel-ssh/src/main/docs/ssh-component.adoc | 4 +
.../apache/camel/component/ssh/SshEndpoint.java | 15 +++
.../apache/camel/component/telegram/telegram.json | 5 +
.../src/main/docs/telegram-component.adoc | 15 ++-
.../camel/component/telegram/TelegramEndpoint.java | 22 +++
.../camel/dsl/yaml/validator/CatalogBodyTypes.java | 14 +-
.../camel/dsl/yaml/validator/TextBodyFlowTest.java | 150 +++++++++++++++++++++
.../camel/maven/packaging/BodyTypesHelper.java | 19 ++-
.../packaging/EndpointSchemaGeneratorMojoTest.java | 12 ++
.../SomeEndpointWithEnumStyleBodyTypes.java | 35 +++++
40 files changed, 650 insertions(+), 54 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/couchbase.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/couchbase.json
index 4681d0125811..f87f52c3261d 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/couchbase.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/couchbase.json
@@ -38,6 +38,11 @@
"CamelCouchbaseViewName": { "index": 4, "kind": "header", "displayName":
"", "group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The view name", "constantName":
"org.apache.camel.component.couchbase.CouchbaseConstants#HEADER_VIEWNAME" },
"CamelCqlResumeQuery": { "index": 5, "kind": "header", "displayName": "",
"group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The resume action to execute when resuming.",
"constantName":
"org.apache.camel.component.couchbase.CouchbaseConstants#COUCHBASE_RESUME_ACTION"
}
},
+ "bodyTypes": {
+ "consumerOut": { "carriers": [ "pojo" ], "javaType":
"com.couchbase.client.java.kv.GetResult", "byOption": [ { "option":
"fullDocument", "value": "false", "carriers": [ "text" ], "javaType":
"java.lang.String" }, { "option": "useView", "value": "true", "carriers": [
"pojo" ], "javaType": "com.couchbase.client.java.kv.GetResult" } ],
"description": "One message per document the query finds, read by its id (the
CamelCouchbaseId header) as the GetResult of the Couchbase SDK: contentAsOb
[...]
+ "producerIn": { "carriers": [ "text", "map", "list", "pojo" ],
"dependsOn": [ "operation" ], "description": "The document that CCB_PUT, the
default, stores as JSON: a Map, a List or a POJO becomes JSON, and text is
stored as a JSON string, so unmarshal JSON text first. Bytes, a stream or no
body fail. CCB_GET and CCB_DEL do not use the body: the id is the
CamelCouchbaseId header" },
+ "producerOut": { "carriers": [ "value" ], "javaType": "java.lang.Boolean",
"dependsOn": [ "operation" ], "byOption": [ { "option": "operation", "value":
"CCB_GET", "carriers": [ "pojo" ], "javaType":
"com.couchbase.client.java.kv.GetResult" }, { "option": "operation", "value":
"CCB_DEL", "carriers": [ "text" ], "javaType": "java.lang.String" } ],
"description": "true for CCB_PUT, the default; the GetResult of the Couchbase
SDK for CCB_GET, and the MutationResult as text for CCB_DEL. [...]
+ },
"properties": {
"protocol": { "index": 0, "kind": "path", "displayName": "Protocol",
"group": "common", "label": "", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The protocol to use" },
"hostname": { "index": 1, "kind": "path", "displayName": "Hostname",
"group": "common", "label": "", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The hostname to use" },
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/fhir.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/fhir.json
index e7797c75d1e1..d122ed869f39 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/fhir.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/fhir.json
@@ -53,6 +53,11 @@
"password": { "index": 25, "kind": "property", "displayName": "Password",
"group": "security", "label": "security", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": true, "security": "secret", "configurationClass":
"org.apache.camel.component.fhir.FhirConfiguration", "configurationField":
"configuration", "description": "Password to use for basic authentication" },
"username": { "index": 26, "kind": "property", "displayName": "Username",
"group": "security", "label": "security", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": true, "security": "secret", "configurationClass":
"org.apache.camel.component.fhir.FhirConfiguration", "configurationField":
"configuration", "description": "Username to use for basic authentication" }
},
+ "bodyTypes": {
+ "consumerOut": { "carriers": [ "pojo" ], "byOption": [ { "option":
"apiName", "value": "TRANSACTION", "carriers": [ "pojo", "text" ] } ],
"description": "One message per poll with the return value of the method: a
MethodOutcome for create, update, patch, delete and validate, and a HAPI FHIR
model object of the fhirVersion for the others, such as the Bundle of a search.
A List is split into one message per resource, and transaction withBundle with
stringBundle gives the response as text" },
+ "producerIn": { "carriers": [ "any" ], "dependsOn": [ "inBody" ],
"description": "The body is used only when inBody names the argument of the
method it is, and then passed as it is, without type conversion:
resourceAsString, stringBundle and url take text (convertBodyTo String first),
and resource, bundle and resources a HAPI FHIR object or a List of them
(unmarshal with fhirJson or fhirXml first). Without inBody the arguments come
from the options and the CamelFhir. headers" },
+ "producerOut": { "carriers": [ "pojo" ], "byOption": [ { "option":
"apiName", "value": "TRANSACTION", "carriers": [ "pojo", "text", "list" ] } ],
"description": "The return value of the method: a MethodOutcome for create,
update, patch, delete and validate, and a HAPI FHIR model object of the
fhirVersion for the others, such as the Bundle of a search or the resource of a
read; marshal a resource or a Bundle with fhirJson or fhirXml to get text.
transaction gives a Bundle for withBund [...]
+ },
"properties": {
"apiName": { "index": 0, "kind": "path", "displayName": "Api Name",
"group": "common", "label": "", "required": true, "type": "enum", "javaType":
"org.apache.camel.component.fhir.internal.FhirApiName", "enum": [
"CAPABILITIES", "CREATE", "DELETE", "HISTORY", "LOAD_PAGE", "META",
"OPERATION", "PATCH", "READ", "SEARCH", "TRANSACTION", "UPDATE", "VALIDATE" ],
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "configurationClass": "org.apache.camel.componen [...]
"methodName": { "index": 1, "kind": "path", "displayName": "Method Name",
"group": "common", "label": "", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.fhir.FhirConfiguration", "configurationField":
"configuration", "description": "What sub operation to use for the selected
operation" },
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/slack.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/slack.json
index c127837baf01..8fd717ae367a 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/slack.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/slack.json
@@ -32,6 +32,11 @@
"token": { "index": 5, "kind": "property", "displayName": "Token",
"group": "token", "label": "token", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "description": "The token to access Slack. This app needs to
have channels:history, groups:history, im:history, mpim:history, channels:read,
groups:read, im:read and mpim:read permissions. The User OAuth Token is the
kind of token needed." },
"webhookUrl": { "index": 6, "kind": "property", "displayName": "Webhook
Url", "group": "webhook", "label": "webhook", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "description": "The incoming webhook URL" }
},
+ "bodyTypes": {
+ "consumerOut": { "carriers": [ "pojo" ], "javaType":
"com.slack.api.model.Message", "description": "One message per new message of
the conversation, the most recent first, or the oldest first with naturalOrder;
the first poll gives the last message of the history. The text is ${body.text}"
},
+ "producerIn": { "carriers": [ "text", "bytes", "stream", "file", "pojo" ],
"description": "The text of the message, or a com.slack.api.model.Message with
its blocks: bytes, a stream or a file are read as text. A Map or another POJO
is sent as its toString(): marshal it first. No body sends no text, which Slack
rejects" },
+ "producerOut": { "carriers": [ "unchanged" ], "description": "Unchanged:
the answer of Slack is not kept" }
+ },
"properties": {
"channel": { "index": 0, "kind": "path", "displayName": "Channel",
"group": "common", "label": "", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The channel name (syntax #name) or
slack user (syntax userName) to send a message directly to an user." },
"token": { "index": 1, "kind": "parameter", "displayName": "Token",
"group": "common", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": true, "security": "secret", "description": "The token to access
Slack. This app needs to have channels:history, groups:history, im:history,
mpim:history, channels:read, groups:read, im:read and mpim:read permissions.
The User OAuth Token is the kind of token needed." },
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/solr.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/solr.json
index 698cf8e42fe4..c5806545bcf2 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/solr.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/solr.json
@@ -51,6 +51,10 @@
"CamelSolrField.": { "index": 9, "kind": "header", "displayName": "",
"group": "producer", "label": "", "required": false, "javaType": "Object",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The prefix of the headers that carry the fields of the
document to insert: the header CamelSolrField.id holds the id field.",
"constantName":
"org.apache.camel.component.solr.SolrConstants#HEADER_FIELD_PREFIX" },
"CamelSolrParam.": { "index": 10, "kind": "header", "displayName": "",
"group": "producer", "label": "", "required": false, "javaType": "String",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The prefix of the headers that carry extra request
parameters: the header CamelSolrParam.commit holds the commit parameter.",
"constantName":
"org.apache.camel.component.solr.SolrConstants#HEADER_PARAM_PREFIX" }
},
+ "bodyTypes": {
+ "producerIn": { "carriers": [ "any" ], "byOption": [ { "option":
"operation", "value": "DELETE", "carriers": [ "text", "list" ] } ],
"description": "What the operation needs: INSERT a Map or a SolrInputDocument,
a List of them or of @Field beans, a JSON array or XML text, or a file; DELETE
the id or, with deleteByQuery=true, the query, as text or a List of text;
SEARCH the query as text or a SolrQuery; PING does not use it. Convert bytes or
a stream to text first. The CamelSolrField. [...]
+ "producerOut": { "carriers": [ "map" ], "description": "The response of
Solr as a Map (a SimpleOrderedMap) with the responseHeader and, for a search,
the documents under response as a SolrDocumentList. Convert it to a
QueryResponse or a SolrPingResponse to read it with SolrJ" }
+ },
"properties": {
"host": { "index": 0, "kind": "path", "displayName": "Host", "group":
"producer", "label": "", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.solr.SolrConfiguration", "configurationField":
"configuration", "description": "The solr instance host name (set to 'default'
to use the host name defined on component level)" },
"port": { "index": 1, "kind": "path", "displayName": "Port", "group":
"producer", "label": "", "required": false, "type": "integer", "javaType":
"int", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": 8983, "configurationClass":
"org.apache.camel.component.solr.SolrConfiguration", "configurationField":
"configuration", "description": "The solr instance port number" },
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-redis.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-redis.json
index d6b8fc72d591..4af7413f7668 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-redis.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-redis.json
@@ -60,6 +60,11 @@
"CamelRedis.Longitude": { "index": 27, "kind": "header", "displayName":
"", "group": "common", "label": "", "required": false, "javaType": "Double",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "Longitude.", "constantName":
"org.apache.camel.component.redis.RedisConstants#LONGITUDE" },
"CamelRedis.Radius": { "index": 28, "kind": "header", "displayName": "",
"group": "common", "label": "", "required": false, "javaType": "Double",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "Radius.", "constantName":
"org.apache.camel.component.redis.RedisConstants#RADIUS" }
},
+ "bodyTypes": {
+ "consumerOut": { "carriers": [ "unknown" ], "description": "The message as
the serializer reads it: with the default JDK serializer the Java object the
publisher serialized, such as the String a PUBLISH of this component sent, with
the channel in the CamelRedis.Channel header. A message that is not Java
serialized, such as one from redis-cli, is dropped with a WARN: set a
StringRedisSerializer as the serializer to receive text" },
+ "producerIn": { "carriers": [ "any" ], "description": "The body is not
used: the key, the value and the other arguments of the command come from
headers, such as CamelRedis.Key and CamelRedis.Value, or CamelRedis.Channel and
CamelRedis.Message for PUBLISH. Set CamelRedis.Value from the body to store the
body: with the default serializer it must be Serializable, so a stream fails" },
+ "producerOut": { "carriers": [ "unchanged" ], "dependsOn": [ "command" ],
"byOption": [ { "option": "command", "value": "SET", "carriers": [ "unchanged"
] }, { "option": "command", "value": "SETEX", "carriers": [ "unchanged" ] }, {
"option": "command", "value": "MSET", "carriers": [ "unchanged" ] }, {
"option": "command", "value": "HSET", "carriers": [ "unchanged" ] }, {
"option": "command", "value": "HMSET", "carriers": [ "unchanged" ] }, {
"option": "command", "value": "HDEL", "car [...]
+ },
"properties": {
"host": { "index": 0, "kind": "path", "displayName": "Host", "group":
"common", "label": "", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.redis.RedisConfiguration", "configurationField":
"configuration", "description": "The host where Redis server is running." },
"port": { "index": 1, "kind": "path", "displayName": "Port", "group":
"common", "label": "", "required": true, "type": "integer", "javaType":
"java.lang.Integer", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.redis.RedisConfiguration", "configurationField":
"configuration", "description": "Redis server port number" },
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ssh.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ssh.json
index dd1c9ac5740b..6fa65e1a1bc7 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ssh.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ssh.json
@@ -63,6 +63,11 @@
"CamelSshStderr": { "index": 2, "kind": "header", "displayName": "",
"group": "common", "label": "", "required": false, "javaType": "InputStream",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The value of this header is a InputStream with the
standard error stream of the executable.", "constantName":
"org.apache.camel.component.ssh.SshConstants#STDERR" },
"CamelSshExitValue": { "index": 3, "kind": "header", "displayName": "",
"group": "common", "label": "", "required": false, "javaType": "Integer",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "important": true, "description": "The value of this header is the exit
value that is returned, after the execution. By convention a non-zero status
exit value indicates abnormal termination. Note that the exit value is OS
dependent.", "constantName": "org.apac [...]
},
+ "bodyTypes": {
+ "consumerOut": { "carriers": [ "stream" ], "description": "The standard
output of the pollCommand as a stream, with the exit value and the standard
error in the CamelSshExitValue and CamelSshStderr headers" },
+ "producerIn": { "carriers": [ "text", "bytes", "stream", "file" ],
"description": "The command to run, as text: bytes, a stream or a file are read
as text. A Map or a POJO is sent as its toString(): build the command as text
first. No body fails" },
+ "producerOut": { "carriers": [ "stream" ], "description": "The standard
output of the command as a stream, with the exit value and the standard error
in the CamelSshExitValue and CamelSshStderr headers; an exit value that is not
0 does not fail the exchange. Convert it to text to read it more than once" }
+ },
"properties": {
"host": { "index": 0, "kind": "path", "displayName": "Host", "group":
"common", "label": "", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.ssh.SshConfiguration", "configurationField":
"configuration", "description": "Sets the hostname of the remote SSH server." },
"port": { "index": 1, "kind": "path", "displayName": "Port", "group":
"common", "label": "", "required": false, "type": "integer", "javaType": "int",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": 22,
"configurationClass": "org.apache.camel.component.ssh.SshConfiguration",
"configurationField": "configuration", "description": "Sets the port number for
the remote SSH server." },
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/telegram.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/telegram.json
index a26ad023217c..2c99fd226779 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/telegram.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/telegram.json
@@ -41,6 +41,11 @@
"CamelTelegramParseMode": { "index": 4, "kind": "header", "displayName":
"", "group": "common", "label": "", "required": false, "javaType":
"org.apache.camel.component.telegram.TelegramParseMode", "enum": [ "HTML",
"MARKDOWN" ], "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "This header is used to format text messages
using HTML or Markdown", "constantName":
"org.apache.camel.component.telegram.TelegramConstants#TELEGRAM_PARSE_MODE" },
"CamelMessageTimestamp": { "index": 5, "kind": "header", "displayName":
"", "group": "common", "label": "", "required": false, "javaType": "long",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The message timestamp.", "constantName":
"org.apache.camel.component.telegram.TelegramConstants#MESSAGE_TIMESTAMP" }
},
+ "bodyTypes": {
+ "consumerOut": { "carriers": [ "pojo", "null" ], "description": "One
message per update: an IncomingMessage for a message or a channel post, with
the chat id in the CamelTelegramChatId header, and the IncomingCallbackQuery,
IncomingInlineQuery, PreCheckoutQuery, ShippingQuery or PaidMediaPurchased of
the other updates; no body for an update of another kind, such as an edited
message" },
+ "producerIn": { "carriers": [ "text", "bytes", "stream", "file", "pojo",
"null" ], "description": "A message of
org.apache.camel.component.telegram.model, such as an OutgoingTextMessage, or
text to send as a text message: a stream or a file is read as text, and a Map
or another POJO is sent as its toString(), so marshal it first. A byte array is
sent as the photo, audio, video or document the CamelTelegramMediaType header
names, and fails without it. No body sends nothing" },
+ "producerOut": { "carriers": [ "pojo", "unchanged" ], "description": "The
MessageResult of the call, with the message sent, or a subclass of it such as
MessageResultString for createInvoiceLink; an answer with ok=false is a
MessageResult too. No body is left as it is" }
+ },
"properties": {
"type": { "index": 0, "kind": "path", "displayName": "Type", "group":
"common", "label": "", "required": true, "type": "enum", "javaType":
"java.lang.String", "enum": [ "bots" ], "deprecated": false, "deprecationNote":
"", "autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.telegram.TelegramConfiguration",
"configurationField": "configuration", "description": "The endpoint type.
Currently, only the 'bots' type is supported." },
"limit": { "index": 1, "kind": "parameter", "displayName": "Limit",
"group": "consumer", "label": "consumer", "required": false, "type": "integer",
"javaType": "java.lang.Integer", "optionalPrefix": "consumer.", "deprecated":
false, "autowired": false, "secret": false, "defaultValue": 100,
"configurationClass":
"org.apache.camel.component.telegram.TelegramConfiguration",
"configurationField": "configuration", "description": "Limit on the number of
updates that can be received in a si [...]
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/couchbase-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/couchbase-component.adoc
index 8d5ad8edda5e..707109794a00 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/couchbase-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/couchbase-component.adoc
@@ -116,8 +116,10 @@
from("couchbase:http://localhost?bucket=myBucket&username=user&password=pass"
The query must include `META().id AS \__id` in the SELECT clause so the
consumer can identify each document.
-When `fullDocument` is `true` (the default), the consumer fetches the complete
document from the KV store using
-the document ID. When `false`, the query result row is used directly as the
message body.
+When `fullDocument` is `true` (the default), the consumer fetches the document
from the KV store by its id, and the
+message body is the `GetResult` of the Couchbase SDK, with the id in the
`CamelCouchbaseId` header: `contentAsObject()`
+gives the JSON document. When `false`, the message body is the query result
row as JSON text, or with views the value the
+view emits.
NOTE: SQL++ queries require a primary index or appropriate secondary index on
the bucket/collection.
Create one with: `CREATE PRIMARY INDEX ON \`myBucket\`` or via the Couchbase
SDK.
@@ -192,6 +194,16 @@
from("couchbase:http://localhost?bucket=myBucket&username=user&password=pass"
+ "&statement=SELECT META().id AS __id, * FROM `myBucket` ORDER BY
META().id DESC LIMIT 10")
----
+== Producing documents
+
+The producer runs the operation of the `operation` option: `CCB_PUT` (the
default) stores the message body as the
+document with the id of the `CamelCouchbaseId` header, `CCB_GET` reads the
document of that id, and `CCB_DEL` deletes
+it. The producer removes the `CamelCouchbaseId` header after each call, so set
it again before the next one.
+
+`CCB_PUT` stores the body as JSON: a Map, a List or a POJO becomes a JSON
document, and text is stored as a JSON string,
+so unmarshal JSON text to a Map first. A byte array, a stream or no body fail.
After the call the message body is `true`
+for `CCB_PUT`, the `GetResult` of the Couchbase SDK for `CCB_GET`, and the
`MutationResult` as text for `CCB_DEL`.
+
== Couchbase SDK compatibility
Using collections and scopes is supported only for Couchbase Server 7.0 and
later.
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/fhir-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/fhir-component.adoc
index ad69d116e9e7..df7f1a144759 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/fhir-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/fhir-component.adoc
@@ -120,3 +120,11 @@ The URI names the API and its method, such as
`fhir://read/resourceById`. The pa
- log:
message: "Found ${body.total} patients"
----
+
+The `inBody` option names the parameter of the method that the message body
is, such as `resourceAsString` in the
+first route. The body is passed as it is, without type conversion, so a
parameter of type String needs a String body:
+convert a byte array or a stream with `convertBodyTo` first. Without `inBody`
the body is not used.
+
+After the call the message body is the result of the method: a `MethodOutcome`
for create, update, patch, delete and
+validate, and a HAPI FHIR model object for the others, such as the `Bundle` of
a search or the resource of a read. Marshal
+a resource or a `Bundle` with `fhirJson` or `fhirXml` to get text.
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/slack-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/slack-component.adoc
index b0708b1d502b..7f26de4031be 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/slack-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/slack-component.adoc
@@ -53,7 +53,12 @@ include::partial$component-endpoint-headers.adoc[]
== Usage
To send a message contained in the message body, a pre-established
-https://api.slack.com/incoming-webhooks[Slack incoming webhook] must be
configured in Slack.
+https://api.slack.com/incoming-webhooks[Slack incoming webhook] must be
configured in Slack, or the producer uses a token
+of a Slack app.
+
+The producer sends the message body as the text of the message: bytes, a
stream or a file are read as text. A
+`com.slack.api.model.Message` body is sent with its blocks and attachments.
Marshal a Map or another object to text
+first, as it is otherwise sent as its `toString()`. The message body is
unchanged after the call.
=== Configuring in Spring XML
@@ -185,7 +190,8 @@ YAML::
----
====
-This way you'll get the last message from `general` channel.
+This way you'll get the last message from `general` channel, as a
`com.slack.api.model.Message`, whose text is
+`${body.text}`.
The consumer will track the timestamp of the last message consumed,
and in the next poll it will consume only newer messages in the channel.
When more than `maxResults` new messages were posted since the previous poll,
the consumer reads the following pages of
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/solr-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/solr-component.adoc
index 9e574e8b94b5..5e8d8ccca062 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/solr-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/solr-component.adoc
@@ -62,16 +62,22 @@ the following. Some operations also require the message
body to be set.
|`INSERT` | File |inserts/updates a document or documents using the given File
(using ContentStreamUpdateRequest)
|`INSERT` | SolrInputDocument or Collection<SolrInputDocument>|inserts/updates
a document or documents based on the given (collection of) SolrInputDocument
|`INSERT` | bean or Collection<bean> |inserts/updates a document or documents
based on values in an
http://wiki.apache.org/solr/Solrj#Directly_adding_POJOs_to_Solr[annotated bean]
-|`INSERT` | String |inserts/updates a document or documents index based on the
given XML or json as string (must follow SolrInputDocument format)
+|`INSERT` | Map or Collection<Map> |inserts/updates a document or documents
with the fields of the Map
+|`INSERT` | String |inserts/updates the documents of the given JSON or XML
text: a JSON array of documents, or XML documents (an `<add>` element is added
when the text does not start with one)
-|`DELETE` | String or Collection<String> | delete a record by ID (or
collection of ids) or by a query (or a collection of queries) when header
"deleteByQuery=true"
+|`DELETE` | String or Collection<String> | delete a record by ID (or
collection of ids) or by a query (or a collection of queries) when the
`deleteByQuery` option or the `CamelSolrDeleteByQuery` header is true
-|`PING` |SolrPing | Pings the solr instance
+|`PING` |n/a | Pings the solr instance
|`SEARCH` |SolrQuery | Performs a search request to the solr instance
|`SEARCH` |QueryRequest | Performs a search request to the solr instance
+|`SEARCH` |String | Performs a search with the query as text, unless the
`CamelSolrQueryString` header holds the query
|=======================================================================
+After each operation the message body is the response of Solr as a Map (a
`SimpleOrderedMap`) with the
+`responseHeader`, and for a search the documents under `response` as a
`SolrDocumentList`. Convert it to a
+`QueryResponse` to read it with SolrJ.
+
== Example
Below is a simple `INSERT`, `DELETE` and `SEARCH` example
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/spring-redis-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/spring-redis-component.adoc
index 302c90ea9268..a9037b6057bb 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/spring-redis-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/spring-redis-component.adoc
@@ -53,7 +53,9 @@ at
https://github.com/apache/camel/tree/main/components/camel-spring-redis/src/t
The producer runs the command of the `command` option, or of the
`CamelRedis.Command` header.
The parameters of the command come from headers, such as `CamelRedis.Key` and
`CamelRedis.Value`, not from the
-message body. The tables below list the parameters of each command. The result
of the command is the message body:
+message body. The tables below list the parameters of each command. The result
of the command becomes the message body,
+and a command without a result, such as `SET`, or a result that is null, such
as `GET` of a missing key, leaves the body
+as it was:
[source,yaml]
----
@@ -156,17 +158,19 @@ these keys:
=== Message headers evaluated by the Redis producer
The producer issues commands to the server, and each command has
-a different set of parameters with specific types. The result from the
-command execution is returned in the message body.
+a different set of parameters with specific types. The result of the
+command becomes the message body. A command whose result is void, and a result
that is null, leave the body as it was.
+The value commands, such as `GET`, `HGET` and `LPOP`, return the object that
was stored: with the default serializer the
+Java object the `CamelRedis.Value` header held.
[width="100%",cols="10%,40%,50%,10%",options="header",]
|=======================================================================
|Hash Commands |Description |Parameters |Result
|`HSET` |Set the string value of a hash field
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.FIELD`/"CamelRedis.Field" (String),
`RedisConstants.VALUE`/"CamelRedis.Value"
(Object) |void
-|`HGET` |Get the value of a hash field |`RedisConstants.KEY`/"CamelRedis.Key"
(String), `RedisConstants.FIELD`/"CamelRedis.Field" (String) |String
+|`HGET` |Get the value of a hash field |`RedisConstants.KEY`/"CamelRedis.Key"
(String), `RedisConstants.FIELD`/"CamelRedis.Field" (String) |Object
|`HSETNX` |Set the value of a hash field only if the field does not exist
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.FIELD`/"CamelRedis.Field" (String),
`RedisConstants.VALUE`/"CamelRedis.Value"
-(Object) |void
+(Object) |Boolean
|`HMSET` |Set multiple hash fields to multiple values
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.VALUES`/"CamelRedis.Values" (Map<String, Object>) |void
|`HMGET` |Get the values of all the given hash fields
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.FIELDS`/"CamelRedis.Fields" (Collection<String>)
|Collection<Object>
|`HINCRBY` |Increment the integer value of a hash field by the given number
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.FIELD`/"CamelRedis.Field" (String),
`RedisConstants.VALUE`/"CamelRedis.Value"
@@ -195,7 +199,7 @@ command execution is returned in the message body.
|`LTRIM` |Trim a list to the specified range
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.START`/"CamelRedis.Start"Long),
`RedisConstants.END`/"CamelRedis.End" (Long) |void
-|`LINDEX` |Get an element from a list by its index
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.INDEX`/"CamelRedis.Index" (Long) |String
+|`LINDEX` |Get an element from a list by its index
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.INDEX`/"CamelRedis.Index" (Long) |Object
|`LINSERT` |Insert an element before or after another element in a list
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.VALUE`/"CamelRedis.Value" (Object),
`RedisConstants.PIVOT`/"CamelRedis.Pivot"
(String), `RedisConstants.POSITION`/"CamelRedis.Position" (String) |Long
@@ -208,7 +212,7 @@ command execution is returned in the message body.
|`LPOP` |Remove and get the first element in a list
|`RedisConstants.KEY`/"CamelRedis.Key" (String) |Object
-|`RPOP` |Remove and get the last element in a list
|`RedisConstants.KEY`/"CamelRedis.Key" (String) |String
+|`RPOP` |Remove and get the last element in a list
|`RedisConstants.KEY`/"CamelRedis.Key" (String) |Object
|`RPOPLPUSH` |Remove the last element in a list, append it to another list and
return
it |`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.DESTINATION`/"CamelRedis.Destination" (String) |Object
@@ -221,20 +225,20 @@ until one is available
|`RedisConstants.KEY`/"CamelRedis.Key" (String), `RedisCo
available |`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.TIMEOUT`/"CamelRedis.Timeout" (Long) |Object
|`BRPOP` |Remove and get the last element in a list, or block until one is
-available |`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.TIMEOUT`/"CamelRedis.Timeout" (Long) |String
+available |`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.TIMEOUT`/"CamelRedis.Timeout" (Long) |Object
|=======================================================================
[width="100%",cols="10%,40%,50%,10%",options="header",]
|=======================================================================
|Set Commands |Description |Parameters |Result
-|`SADD` |Add one or more members to a set
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.VALUE`/"CamelRedis.Value" (Object) |Boolean
+|`SADD` |Add one or more members to a set
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.VALUE`/"CamelRedis.Value" (Object) |Long
|`SMEMBERS` |Get all the members in a set
|`RedisConstants.KEY`/"CamelRedis.Key" (String) |Set<Object>
-|`SREM` |Remove one or more members from a set
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.VALUE`/"CamelRedis.Value" (Object) |Boolean
+|`SREM` |Remove one or more members from a set
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.VALUE`/"CamelRedis.Value" (Object) |Long
-|`SPOP` |Remove and return a random member from a set
|`RedisConstants.KEY`/"CamelRedis.Key" (String) |String
+|`SPOP` |Remove and return a random member from a set
|`RedisConstants.KEY`/"CamelRedis.Key" (String) |Object
|`SMOVE` |Move a member from one set to another
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.VALUE`/"CamelRedis.Value" (Object),
`RedisConstants.DESTINATION`/"CamelRedis.Destination" (String) |Boolean
@@ -258,7 +262,7 @@ available |`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.TIMEO
|`SDIFFSTORE` |Subtract multiple sets and store the resulting set in a key
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.KEYS`/"CamelRedis.Keys" (String),
`RedisConstants.DESTINATION`/"CamelRedis.Destination" (String) |void
-|`SRANDMEMBER` |Get one or multiple random members from a set
|`RedisConstants.KEY`/"CamelRedis.Key" (String) |String
+|`SRANDMEMBER` |Get one or multiple random members from a set
|`RedisConstants.KEY`/"CamelRedis.Key" (String) |Object
|=======================================================================
[width="100%",cols="10%,40%,50%,10%",options="header",]
@@ -272,7 +276,7 @@ already exists |`RedisConstants.KEY`/"CamelRedis.Key"
(String), `RedisConstants.
|`ZRANGE` |Return a range of members in a sorted set, by index
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.START`/"CamelRedis.Start"Long),
`RedisConstants.END`/"CamelRedis.End" (Long),
`RedisConstants.WITHSCORE`/"CamelRedis.WithScore" (Boolean) |Object
-|`ZREM` |Remove one or more members from a sorted set
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.VALUE`/"CamelRedis.Value" (Object) |Boolean
+|`ZREM` |Remove one or more members from a sorted set
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.VALUE`/"CamelRedis.Value" (Object) |Long
|`ZINCRBY` |Increment the score of a member in a sorted set
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.VALUE`/"CamelRedis.Value" (Object),
`RedisConstants.INCREMENT`/"CamelRedis.Increment"
(Double) |Double
@@ -362,9 +366,9 @@ new key |`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.KEYS`/"
|`DEL` |Delete a key |`RedisConstants.KEYS`/"CamelRedis.Keys" (String) |void
-|`TYPE` |Determine the type stored at key
|`RedisConstants.KEY`/"CamelRedis.Key" (String) |DataType
+|`TYPE` |Determine the type stored at key
|`RedisConstants.KEY`/"CamelRedis.Key" (String) |String
-|`KEYS` |Find all keys matching the given pattern
|`RedisConstants.PATERN`/"CamelRedis.Pattern" (String) |Collection<String>
+|`KEYS` |Find all keys matching the given pattern
|`RedisConstants.PATERN`/"CamelRedis.Pattern" (String) |Set<String>
|`RANDOMKEY` |Return a random key from the keyspace
|`RedisConstants.PATERN`/"CamelRedis.Pattern" (String),
`RedisConstants.VALUE`/"CamelRedis.Value" (String) |String
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ssh-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ssh-component.adoc
index e1b2e38de453..79f1fabccde9 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ssh-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/ssh-component.adoc
@@ -50,6 +50,10 @@ When the SSH Component is used as a Producer
(`.to("ssh://...")`), it
will send the message body as the command to execute on the remote SSH
server.
+After the call, the message body is the standard output of the command as a
stream, with the exit value in the
+`CamelSshExitValue` header and the standard error, as a stream as well, in the
`CamelSshStderr` header. An exit value
+that is not 0 does not fail the exchange. The polling consumer gives the
output of its `pollCommand` the same way.
+
Here is an example of this. Note that the command has
a newline (`+ +`).
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/telegram-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/telegram-component.adoc
index 1c01a0531f03..decdf4ee0d9e 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/telegram-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/telegram-component.adoc
@@ -123,7 +123,7 @@ The following message bodies are allowed for a producer
endpoint (messages of ty
| `EditMessageMediaMessage` | To edit animation, audio, document, photo, or
video messages. (editMessageMedia)
| `EditMessageReplyMarkupMessage` | To edit only the reply markup of a
message. (editMessageReplyMarkup)
| `EditMessageDelete` | To delete a message, including service messages.
(deleteMessage)
-| `SendLocationMessage` | To send a location (setSendLocation)
+| `SendLocationMessage` | To send a location (sendLocation)
| `EditMessageLiveLocationMessage` | To send changes to a live location
(editMessageLiveLocation)
| `StopMessageLiveLocationMessage` | To stop updating a live location message
sent by the bot or via the bot (for inline bots) before live_period expires
(stopMessageLiveLocation)
| `SendVenueMessage` | To send information about a venue (sendVenue)
@@ -136,11 +136,15 @@ The following message bodies are allowed for a producer
endpoint (messages of ty
| `GetStarTransactionsMessage` | To get the list of bot's Telegram Star
transactions (getStarTransactions)
| `RefundStarPaymentMessage` | To refund a successful payment in Telegram
Stars (refundStarPayment)
| `EditUserStarSubscriptionMessage` | To cancel or re-enable extension of a
subscription paid in Telegram Stars (editUserStarSubscription)
-| `byte[]` | To send any media type supported. It requires the
`CamelTelegramMediaType` header to be set to the appropriate media type
+| `byte[]` | To send a photo, an audio, a video or a document, as the
`CamelTelegramMediaType` header names (`PHOTO_PNG`, `PHOTO_JPG`, `AUDIO`,
`VIDEO` or `DOCUMENT`). It fails without the header. A stream or a file is sent
as text, so convert it to `byte[]` to send it as media
| `String` | To send a text message to a chat. It gets converted automatically
into a `OutgoingTextMessage`
|===================================================
+Any other body is sent as text, so marshal a Map or another object first, as
it is otherwise sent as its `toString()`.
+After the call the message body is the `MessageResult` of the call, with the
message sent, or a subclass of it, such as
+`MessageResultString` for `CreateInvoiceLinkMessage`. A message body that is
null sends nothing, and stays null.
+
=== Consumer
@@ -204,11 +208,16 @@ Supported types for incoming messages are
|===================================================
| Java Type | Description
-| `IncomingMessage` | The full object representation of an incoming message
+| `IncomingMessage` | The full object representation of an incoming message or
channel post, with the chat id in the `CamelTelegramChatId` header
| `String` | The content of the message, for text messages only
+| `IncomingCallbackQuery` | A callback query, from a button of an inline
keyboard
+| `IncomingInlineQuery` | An inline query
+| `PreCheckoutQuery`, `ShippingQuery`, `PaidMediaPurchased` | The payment
updates, of the package `org.apache.camel.component.telegram.model.payments`
|===================================================
+An update of another kind, such as an edited message, gives a message with no
body.
+
=== Reactive Chat-Bot Example
diff --git
a/components/camel-couchbase/src/generated/resources/META-INF/org/apache/camel/component/couchbase/couchbase.json
b/components/camel-couchbase/src/generated/resources/META-INF/org/apache/camel/component/couchbase/couchbase.json
index 4681d0125811..f87f52c3261d 100644
---
a/components/camel-couchbase/src/generated/resources/META-INF/org/apache/camel/component/couchbase/couchbase.json
+++
b/components/camel-couchbase/src/generated/resources/META-INF/org/apache/camel/component/couchbase/couchbase.json
@@ -38,6 +38,11 @@
"CamelCouchbaseViewName": { "index": 4, "kind": "header", "displayName":
"", "group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The view name", "constantName":
"org.apache.camel.component.couchbase.CouchbaseConstants#HEADER_VIEWNAME" },
"CamelCqlResumeQuery": { "index": 5, "kind": "header", "displayName": "",
"group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The resume action to execute when resuming.",
"constantName":
"org.apache.camel.component.couchbase.CouchbaseConstants#COUCHBASE_RESUME_ACTION"
}
},
+ "bodyTypes": {
+ "consumerOut": { "carriers": [ "pojo" ], "javaType":
"com.couchbase.client.java.kv.GetResult", "byOption": [ { "option":
"fullDocument", "value": "false", "carriers": [ "text" ], "javaType":
"java.lang.String" }, { "option": "useView", "value": "true", "carriers": [
"pojo" ], "javaType": "com.couchbase.client.java.kv.GetResult" } ],
"description": "One message per document the query finds, read by its id (the
CamelCouchbaseId header) as the GetResult of the Couchbase SDK: contentAsOb
[...]
+ "producerIn": { "carriers": [ "text", "map", "list", "pojo" ],
"dependsOn": [ "operation" ], "description": "The document that CCB_PUT, the
default, stores as JSON: a Map, a List or a POJO becomes JSON, and text is
stored as a JSON string, so unmarshal JSON text first. Bytes, a stream or no
body fail. CCB_GET and CCB_DEL do not use the body: the id is the
CamelCouchbaseId header" },
+ "producerOut": { "carriers": [ "value" ], "javaType": "java.lang.Boolean",
"dependsOn": [ "operation" ], "byOption": [ { "option": "operation", "value":
"CCB_GET", "carriers": [ "pojo" ], "javaType":
"com.couchbase.client.java.kv.GetResult" }, { "option": "operation", "value":
"CCB_DEL", "carriers": [ "text" ], "javaType": "java.lang.String" } ],
"description": "true for CCB_PUT, the default; the GetResult of the Couchbase
SDK for CCB_GET, and the MutationResult as text for CCB_DEL. [...]
+ },
"properties": {
"protocol": { "index": 0, "kind": "path", "displayName": "Protocol",
"group": "common", "label": "", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The protocol to use" },
"hostname": { "index": 1, "kind": "path", "displayName": "Hostname",
"group": "common", "label": "", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The hostname to use" },
diff --git a/components/camel-couchbase/src/main/docs/couchbase-component.adoc
b/components/camel-couchbase/src/main/docs/couchbase-component.adoc
index 8d5ad8edda5e..707109794a00 100644
--- a/components/camel-couchbase/src/main/docs/couchbase-component.adoc
+++ b/components/camel-couchbase/src/main/docs/couchbase-component.adoc
@@ -116,8 +116,10 @@
from("couchbase:http://localhost?bucket=myBucket&username=user&password=pass"
The query must include `META().id AS \__id` in the SELECT clause so the
consumer can identify each document.
-When `fullDocument` is `true` (the default), the consumer fetches the complete
document from the KV store using
-the document ID. When `false`, the query result row is used directly as the
message body.
+When `fullDocument` is `true` (the default), the consumer fetches the document
from the KV store by its id, and the
+message body is the `GetResult` of the Couchbase SDK, with the id in the
`CamelCouchbaseId` header: `contentAsObject()`
+gives the JSON document. When `false`, the message body is the query result
row as JSON text, or with views the value the
+view emits.
NOTE: SQL++ queries require a primary index or appropriate secondary index on
the bucket/collection.
Create one with: `CREATE PRIMARY INDEX ON \`myBucket\`` or via the Couchbase
SDK.
@@ -192,6 +194,16 @@
from("couchbase:http://localhost?bucket=myBucket&username=user&password=pass"
+ "&statement=SELECT META().id AS __id, * FROM `myBucket` ORDER BY
META().id DESC LIMIT 10")
----
+== Producing documents
+
+The producer runs the operation of the `operation` option: `CCB_PUT` (the
default) stores the message body as the
+document with the id of the `CamelCouchbaseId` header, `CCB_GET` reads the
document of that id, and `CCB_DEL` deletes
+it. The producer removes the `CamelCouchbaseId` header after each call, so set
it again before the next one.
+
+`CCB_PUT` stores the body as JSON: a Map, a List or a POJO becomes a JSON
document, and text is stored as a JSON string,
+so unmarshal JSON text to a Map first. A byte array, a stream or no body fail.
After the call the message body is `true`
+for `CCB_PUT`, the `GetResult` of the Couchbase SDK for `CCB_GET`, and the
`MutationResult` as text for `CCB_DEL`.
+
== Couchbase SDK compatibility
Using collections and scopes is supported only for Couchbase Server 7.0 and
later.
diff --git
a/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseEndpoint.java
b/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseEndpoint.java
index d83117e80425..60da83bcdfc1 100644
---
a/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseEndpoint.java
+++
b/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseEndpoint.java
@@ -39,6 +39,9 @@ import org.apache.camel.Category;
import org.apache.camel.Consumer;
import org.apache.camel.Processor;
import org.apache.camel.Producer;
+import org.apache.camel.spi.BodyType;
+import org.apache.camel.spi.BodyType.Carrier;
+import org.apache.camel.spi.BodyTypes;
import org.apache.camel.spi.EndpointServiceLocation;
import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.UriEndpoint;
@@ -63,6 +66,31 @@ import static
org.apache.camel.component.couchbase.CouchbaseConstants.DEFAULT_VI
*/
@UriEndpoint(firstVersion = "2.19.0", scheme = "couchbase", title =
"Couchbase", syntax = "couchbase:protocol://hostname:port",
category = { Category.DATABASE }, headersClass =
CouchbaseConstants.class)
+@BodyTypes(consumerOut = @BodyType(value = Carrier.POJO, javaType =
"com.couchbase.client.java.kv.GetResult",
+ byOption = {
+ @BodyType.When(option =
"fullDocument", value = "false", carriers = Carrier.TEXT,
+ javaType =
"java.lang.String"),
+ @BodyType.When(option = "useView",
value = "true", carriers = Carrier.POJO,
+ javaType =
"com.couchbase.client.java.kv.GetResult") },
+ description = "One message per document the
query finds, read by its id (the"
+ + " CamelCouchbaseId header)
as the GetResult of the Couchbase SDK:"
+ + " contentAsObject() gives
the JSON document. With fullDocument=false the row"
+ + " of the SQL++ query as
JSON text, or with useView=true the value the view"
+ + " emits"),
+ producerIn = @BodyType(value = { Carrier.TEXT, Carrier.MAP,
Carrier.LIST, Carrier.POJO }, dependsOn = "operation",
+ description = "The document that CCB_PUT,
the default, stores as JSON: a Map, a List or a"
+ + " POJO becomes JSON, and
text is stored as a JSON string, so unmarshal JSON"
+ + " text first. Bytes, a
stream or no body fail. CCB_GET and CCB_DEL do not use"
+ + " the body: the id is the
CamelCouchbaseId header"),
+ producerOut = @BodyType(value = Carrier.VALUE, javaType =
"java.lang.Boolean", dependsOn = "operation",
+ byOption = {
+ @BodyType.When(option =
"operation", value = "CCB_GET", carriers = Carrier.POJO,
+ javaType =
"com.couchbase.client.java.kv.GetResult"),
+ @BodyType.When(option =
"operation", value = "CCB_DEL", carriers = Carrier.TEXT,
+ javaType =
"java.lang.String") },
+ description = "true for CCB_PUT, the
default; the GetResult of the Couchbase SDK for"
+ + " CCB_GET, and the
MutationResult as text for CCB_DEL. The producer removes"
+ + " the CamelCouchbaseId
header"))
public class CouchbaseEndpoint extends ScheduledPollEndpoint implements
EndpointServiceLocation {
@UriPath
diff --git
a/components/camel-fhir/camel-fhir-component/src/generated/resources/META-INF/org/apache/camel/component/fhir/fhir.json
b/components/camel-fhir/camel-fhir-component/src/generated/resources/META-INF/org/apache/camel/component/fhir/fhir.json
index e7797c75d1e1..d122ed869f39 100644
---
a/components/camel-fhir/camel-fhir-component/src/generated/resources/META-INF/org/apache/camel/component/fhir/fhir.json
+++
b/components/camel-fhir/camel-fhir-component/src/generated/resources/META-INF/org/apache/camel/component/fhir/fhir.json
@@ -53,6 +53,11 @@
"password": { "index": 25, "kind": "property", "displayName": "Password",
"group": "security", "label": "security", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": true, "security": "secret", "configurationClass":
"org.apache.camel.component.fhir.FhirConfiguration", "configurationField":
"configuration", "description": "Password to use for basic authentication" },
"username": { "index": 26, "kind": "property", "displayName": "Username",
"group": "security", "label": "security", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": true, "security": "secret", "configurationClass":
"org.apache.camel.component.fhir.FhirConfiguration", "configurationField":
"configuration", "description": "Username to use for basic authentication" }
},
+ "bodyTypes": {
+ "consumerOut": { "carriers": [ "pojo" ], "byOption": [ { "option":
"apiName", "value": "TRANSACTION", "carriers": [ "pojo", "text" ] } ],
"description": "One message per poll with the return value of the method: a
MethodOutcome for create, update, patch, delete and validate, and a HAPI FHIR
model object of the fhirVersion for the others, such as the Bundle of a search.
A List is split into one message per resource, and transaction withBundle with
stringBundle gives the response as text" },
+ "producerIn": { "carriers": [ "any" ], "dependsOn": [ "inBody" ],
"description": "The body is used only when inBody names the argument of the
method it is, and then passed as it is, without type conversion:
resourceAsString, stringBundle and url take text (convertBodyTo String first),
and resource, bundle and resources a HAPI FHIR object or a List of them
(unmarshal with fhirJson or fhirXml first). Without inBody the arguments come
from the options and the CamelFhir. headers" },
+ "producerOut": { "carriers": [ "pojo" ], "byOption": [ { "option":
"apiName", "value": "TRANSACTION", "carriers": [ "pojo", "text", "list" ] } ],
"description": "The return value of the method: a MethodOutcome for create,
update, patch, delete and validate, and a HAPI FHIR model object of the
fhirVersion for the others, such as the Bundle of a search or the resource of a
read; marshal a resource or a Bundle with fhirJson or fhirXml to get text.
transaction gives a Bundle for withBund [...]
+ },
"properties": {
"apiName": { "index": 0, "kind": "path", "displayName": "Api Name",
"group": "common", "label": "", "required": true, "type": "enum", "javaType":
"org.apache.camel.component.fhir.internal.FhirApiName", "enum": [
"CAPABILITIES", "CREATE", "DELETE", "HISTORY", "LOAD_PAGE", "META",
"OPERATION", "PATCH", "READ", "SEARCH", "TRANSACTION", "UPDATE", "VALIDATE" ],
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "configurationClass": "org.apache.camel.componen [...]
"methodName": { "index": 1, "kind": "path", "displayName": "Method Name",
"group": "common", "label": "", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.fhir.FhirConfiguration", "configurationField":
"configuration", "description": "What sub operation to use for the selected
operation" },
diff --git
a/components/camel-fhir/camel-fhir-component/src/main/docs/fhir-component.adoc
b/components/camel-fhir/camel-fhir-component/src/main/docs/fhir-component.adoc
index ad69d116e9e7..df7f1a144759 100644
---
a/components/camel-fhir/camel-fhir-component/src/main/docs/fhir-component.adoc
+++
b/components/camel-fhir/camel-fhir-component/src/main/docs/fhir-component.adoc
@@ -120,3 +120,11 @@ The URI names the API and its method, such as
`fhir://read/resourceById`. The pa
- log:
message: "Found ${body.total} patients"
----
+
+The `inBody` option names the parameter of the method that the message body
is, such as `resourceAsString` in the
+first route. The body is passed as it is, without type conversion, so a
parameter of type String needs a String body:
+convert a byte array or a stream with `convertBodyTo` first. Without `inBody`
the body is not used.
+
+After the call the message body is the result of the method: a `MethodOutcome`
for create, update, patch, delete and
+validate, and a HAPI FHIR model object for the others, such as the `Bundle` of
a search or the resource of a read. Marshal
+a resource or a `Bundle` with `fhirJson` or `fhirXml` to get text.
diff --git
a/components/camel-fhir/camel-fhir-component/src/main/java/org/apache/camel/component/fhir/FhirEndpoint.java
b/components/camel-fhir/camel-fhir-component/src/main/java/org/apache/camel/component/fhir/FhirEndpoint.java
index 63cf16681057..39eef10f8564 100644
---
a/components/camel-fhir/camel-fhir-component/src/main/java/org/apache/camel/component/fhir/FhirEndpoint.java
+++
b/components/camel-fhir/camel-fhir-component/src/main/java/org/apache/camel/component/fhir/FhirEndpoint.java
@@ -42,6 +42,9 @@ import
org.apache.camel.component.fhir.internal.FhirApiCollection;
import org.apache.camel.component.fhir.internal.FhirApiName;
import org.apache.camel.component.fhir.internal.FhirConstants;
import org.apache.camel.component.fhir.internal.FhirPropertiesHelper;
+import org.apache.camel.spi.BodyType;
+import org.apache.camel.spi.BodyType.Carrier;
+import org.apache.camel.spi.BodyTypes;
import org.apache.camel.spi.EndpointServiceLocation;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.spi.UriParam;
@@ -55,6 +58,30 @@ import
org.apache.camel.support.component.ApiMethodPropertiesHelper;
@UriEndpoint(firstVersion = "2.23.0", scheme = "fhir", title = "FHIR", syntax
= "fhir:apiName/methodName",
apiSyntax = "apiName/methodName",
category = { Category.API })
+@BodyTypes(consumerOut = @BodyType(value = Carrier.POJO,
+ byOption = @BodyType.When(option =
"apiName", value = "TRANSACTION",
+ carriers = {
Carrier.POJO, Carrier.TEXT }),
+ description = "One message per poll with
the return value of the method: a MethodOutcome"
+ + " for create, update,
patch, delete and validate, and a HAPI FHIR model"
+ + " object of the fhirVersion
for the others, such as the Bundle of a search."
+ + " A List is split into one
message per resource, and transaction withBundle"
+ + " with stringBundle gives
the response as text"),
+ producerIn = @BodyType(value = Carrier.ANY, dependsOn = "inBody",
+ description = "The body is used only when
inBody names the argument of the method it is,"
+ + " and then passed as it is,
without type conversion: resourceAsString,"
+ + " stringBundle and url take
text (convertBodyTo String first), and resource,"
+ + " bundle and resources a
HAPI FHIR object or a List of them (unmarshal with"
+ + " fhirJson or fhirXml
first). Without inBody the arguments come from the"
+ + " options and the CamelFhir.
headers"),
+ producerOut = @BodyType(value = Carrier.POJO,
+ byOption = @BodyType.When(option =
"apiName", value = "TRANSACTION",
+ carriers = {
Carrier.POJO, Carrier.TEXT, Carrier.LIST }),
+ description = "The return value of the
method: a MethodOutcome for create, update, patch,"
+ + " delete and validate, and
a HAPI FHIR model object of the fhirVersion for"
+ + " the others, such as the
Bundle of a search or the resource of a read;"
+ + " marshal a resource or a
Bundle with fhirJson or fhirXml to get text."
+ + " transaction gives a
Bundle for withBundle with bundle, the response as"
+ + " text with stringBundle,
and a List of the resources for withResources"))
public class FhirEndpoint extends AbstractApiEndpoint<FhirApiName,
FhirConfiguration> implements EndpointServiceLocation {
private static final String EXTRA_PARAMETERS_PROPERTY = "extraParameters";
diff --git
a/components/camel-slack/src/generated/resources/META-INF/org/apache/camel/component/slack/slack.json
b/components/camel-slack/src/generated/resources/META-INF/org/apache/camel/component/slack/slack.json
index c127837baf01..8fd717ae367a 100644
---
a/components/camel-slack/src/generated/resources/META-INF/org/apache/camel/component/slack/slack.json
+++
b/components/camel-slack/src/generated/resources/META-INF/org/apache/camel/component/slack/slack.json
@@ -32,6 +32,11 @@
"token": { "index": 5, "kind": "property", "displayName": "Token",
"group": "token", "label": "token", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "description": "The token to access Slack. This app needs to
have channels:history, groups:history, im:history, mpim:history, channels:read,
groups:read, im:read and mpim:read permissions. The User OAuth Token is the
kind of token needed." },
"webhookUrl": { "index": 6, "kind": "property", "displayName": "Webhook
Url", "group": "webhook", "label": "webhook", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "description": "The incoming webhook URL" }
},
+ "bodyTypes": {
+ "consumerOut": { "carriers": [ "pojo" ], "javaType":
"com.slack.api.model.Message", "description": "One message per new message of
the conversation, the most recent first, or the oldest first with naturalOrder;
the first poll gives the last message of the history. The text is ${body.text}"
},
+ "producerIn": { "carriers": [ "text", "bytes", "stream", "file", "pojo" ],
"description": "The text of the message, or a com.slack.api.model.Message with
its blocks: bytes, a stream or a file are read as text. A Map or another POJO
is sent as its toString(): marshal it first. No body sends no text, which Slack
rejects" },
+ "producerOut": { "carriers": [ "unchanged" ], "description": "Unchanged:
the answer of Slack is not kept" }
+ },
"properties": {
"channel": { "index": 0, "kind": "path", "displayName": "Channel",
"group": "common", "label": "", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The channel name (syntax #name) or
slack user (syntax userName) to send a message directly to an user." },
"token": { "index": 1, "kind": "parameter", "displayName": "Token",
"group": "common", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": true, "security": "secret", "description": "The token to access
Slack. This app needs to have channels:history, groups:history, im:history,
mpim:history, channels:read, groups:read, im:read and mpim:read permissions.
The User OAuth Token is the kind of token needed." },
diff --git a/components/camel-slack/src/main/docs/slack-component.adoc
b/components/camel-slack/src/main/docs/slack-component.adoc
index b0708b1d502b..7f26de4031be 100644
--- a/components/camel-slack/src/main/docs/slack-component.adoc
+++ b/components/camel-slack/src/main/docs/slack-component.adoc
@@ -53,7 +53,12 @@ include::partial$component-endpoint-headers.adoc[]
== Usage
To send a message contained in the message body, a pre-established
-https://api.slack.com/incoming-webhooks[Slack incoming webhook] must be
configured in Slack.
+https://api.slack.com/incoming-webhooks[Slack incoming webhook] must be
configured in Slack, or the producer uses a token
+of a Slack app.
+
+The producer sends the message body as the text of the message: bytes, a
stream or a file are read as text. A
+`com.slack.api.model.Message` body is sent with its blocks and attachments.
Marshal a Map or another object to text
+first, as it is otherwise sent as its `toString()`. The message body is
unchanged after the call.
=== Configuring in Spring XML
@@ -185,7 +190,8 @@ YAML::
----
====
-This way you'll get the last message from `general` channel.
+This way you'll get the last message from `general` channel, as a
`com.slack.api.model.Message`, whose text is
+`${body.text}`.
The consumer will track the timestamp of the last message consumed,
and in the next poll it will consume only newer messages in the channel.
When more than `maxResults` new messages were posted since the previous poll,
the consumer reads the following pages of
diff --git
a/components/camel-slack/src/main/java/org/apache/camel/component/slack/SlackEndpoint.java
b/components/camel-slack/src/main/java/org/apache/camel/component/slack/SlackEndpoint.java
index fb94edc48f68..dad140f3fd68 100644
---
a/components/camel-slack/src/main/java/org/apache/camel/component/slack/SlackEndpoint.java
+++
b/components/camel-slack/src/main/java/org/apache/camel/component/slack/SlackEndpoint.java
@@ -22,6 +22,9 @@ import org.apache.camel.Consumer;
import org.apache.camel.Processor;
import org.apache.camel.Producer;
import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.spi.BodyType;
+import org.apache.camel.spi.BodyType.Carrier;
+import org.apache.camel.spi.BodyTypes;
import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.spi.UriParam;
@@ -34,6 +37,17 @@ import org.apache.camel.util.ObjectHelper;
*/
@UriEndpoint(firstVersion = "2.16.0", scheme = "slack", title = "Slack",
syntax = "slack:channel",
category = { Category.SOCIAL })
+@BodyTypes(consumerOut = @BodyType(value = Carrier.POJO, javaType =
"com.slack.api.model.Message",
+ description = "One message per new message
of the conversation, the most recent first, or"
+ + " the oldest first with
naturalOrder; the first poll gives the last message"
+ + " of the history. The text
is ${body.text}"),
+ producerIn = @BodyType(value = { Carrier.TEXT, Carrier.BYTES,
Carrier.STREAM, Carrier.FILE, Carrier.POJO },
+ description = "The text of the message, or a
com.slack.api.model.Message with its blocks:"
+ + " bytes, a stream or a file
are read as text. A Map or another POJO is sent"
+ + " as its toString(): marshal
it first. No body sends no text, which Slack"
+ + " rejects"),
+ producerOut = @BodyType(value = Carrier.UNCHANGED,
+ description = "Unchanged: the answer of
Slack is not kept"))
public class SlackEndpoint extends ScheduledPollEndpoint {
@UriParam(defaultValue = "" + SlackConsumer.DEFAULT_CONSUMER_DELAY,
javaType = "java.time.Duration",
diff --git
a/components/camel-solr/src/generated/resources/META-INF/org/apache/camel/component/solr/solr.json
b/components/camel-solr/src/generated/resources/META-INF/org/apache/camel/component/solr/solr.json
index 698cf8e42fe4..c5806545bcf2 100644
---
a/components/camel-solr/src/generated/resources/META-INF/org/apache/camel/component/solr/solr.json
+++
b/components/camel-solr/src/generated/resources/META-INF/org/apache/camel/component/solr/solr.json
@@ -51,6 +51,10 @@
"CamelSolrField.": { "index": 9, "kind": "header", "displayName": "",
"group": "producer", "label": "", "required": false, "javaType": "Object",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The prefix of the headers that carry the fields of the
document to insert: the header CamelSolrField.id holds the id field.",
"constantName":
"org.apache.camel.component.solr.SolrConstants#HEADER_FIELD_PREFIX" },
"CamelSolrParam.": { "index": 10, "kind": "header", "displayName": "",
"group": "producer", "label": "", "required": false, "javaType": "String",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The prefix of the headers that carry extra request
parameters: the header CamelSolrParam.commit holds the commit parameter.",
"constantName":
"org.apache.camel.component.solr.SolrConstants#HEADER_PARAM_PREFIX" }
},
+ "bodyTypes": {
+ "producerIn": { "carriers": [ "any" ], "byOption": [ { "option":
"operation", "value": "DELETE", "carriers": [ "text", "list" ] } ],
"description": "What the operation needs: INSERT a Map or a SolrInputDocument,
a List of them or of @Field beans, a JSON array or XML text, or a file; DELETE
the id or, with deleteByQuery=true, the query, as text or a List of text;
SEARCH the query as text or a SolrQuery; PING does not use it. Convert bytes or
a stream to text first. The CamelSolrField. [...]
+ "producerOut": { "carriers": [ "map" ], "description": "The response of
Solr as a Map (a SimpleOrderedMap) with the responseHeader and, for a search,
the documents under response as a SolrDocumentList. Convert it to a
QueryResponse or a SolrPingResponse to read it with SolrJ" }
+ },
"properties": {
"host": { "index": 0, "kind": "path", "displayName": "Host", "group":
"producer", "label": "", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.solr.SolrConfiguration", "configurationField":
"configuration", "description": "The solr instance host name (set to 'default'
to use the host name defined on component level)" },
"port": { "index": 1, "kind": "path", "displayName": "Port", "group":
"producer", "label": "", "required": false, "type": "integer", "javaType":
"int", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": 8983, "configurationClass":
"org.apache.camel.component.solr.SolrConfiguration", "configurationField":
"configuration", "description": "The solr instance port number" },
diff --git a/components/camel-solr/src/main/docs/solr-component.adoc
b/components/camel-solr/src/main/docs/solr-component.adoc
index 9e574e8b94b5..5e8d8ccca062 100644
--- a/components/camel-solr/src/main/docs/solr-component.adoc
+++ b/components/camel-solr/src/main/docs/solr-component.adoc
@@ -62,16 +62,22 @@ the following. Some operations also require the message
body to be set.
|`INSERT` | File |inserts/updates a document or documents using the given File
(using ContentStreamUpdateRequest)
|`INSERT` | SolrInputDocument or Collection<SolrInputDocument>|inserts/updates
a document or documents based on the given (collection of) SolrInputDocument
|`INSERT` | bean or Collection<bean> |inserts/updates a document or documents
based on values in an
http://wiki.apache.org/solr/Solrj#Directly_adding_POJOs_to_Solr[annotated bean]
-|`INSERT` | String |inserts/updates a document or documents index based on the
given XML or json as string (must follow SolrInputDocument format)
+|`INSERT` | Map or Collection<Map> |inserts/updates a document or documents
with the fields of the Map
+|`INSERT` | String |inserts/updates the documents of the given JSON or XML
text: a JSON array of documents, or XML documents (an `<add>` element is added
when the text does not start with one)
-|`DELETE` | String or Collection<String> | delete a record by ID (or
collection of ids) or by a query (or a collection of queries) when header
"deleteByQuery=true"
+|`DELETE` | String or Collection<String> | delete a record by ID (or
collection of ids) or by a query (or a collection of queries) when the
`deleteByQuery` option or the `CamelSolrDeleteByQuery` header is true
-|`PING` |SolrPing | Pings the solr instance
+|`PING` |n/a | Pings the solr instance
|`SEARCH` |SolrQuery | Performs a search request to the solr instance
|`SEARCH` |QueryRequest | Performs a search request to the solr instance
+|`SEARCH` |String | Performs a search with the query as text, unless the
`CamelSolrQueryString` header holds the query
|=======================================================================
+After each operation the message body is the response of Solr as a Map (a
`SimpleOrderedMap`) with the
+`responseHeader`, and for a search the documents under `response` as a
`SolrDocumentList`. Convert it to a
+`QueryResponse` to read it with SolrJ.
+
== Example
Below is a simple `INSERT`, `DELETE` and `SEARCH` example
diff --git
a/components/camel-solr/src/main/java/org/apache/camel/component/solr/SolrEndpoint.java
b/components/camel-solr/src/main/java/org/apache/camel/component/solr/SolrEndpoint.java
index f5f2fd66dd88..06c5ee7c0183 100644
---
a/components/camel-solr/src/main/java/org/apache/camel/component/solr/SolrEndpoint.java
+++
b/components/camel-solr/src/main/java/org/apache/camel/component/solr/SolrEndpoint.java
@@ -30,6 +30,9 @@ import org.apache.camel.Category;
import org.apache.camel.Consumer;
import org.apache.camel.Processor;
import org.apache.camel.Producer;
+import org.apache.camel.spi.BodyType;
+import org.apache.camel.spi.BodyType.Carrier;
+import org.apache.camel.spi.BodyTypes;
import org.apache.camel.spi.EndpointServiceLocation;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.spi.UriParam;
@@ -50,6 +53,20 @@ import org.slf4j.LoggerFactory;
*/
@UriEndpoint(firstVersion = "4.8.0", scheme = "solr", title = "Solr", syntax =
"solr:host:port/basePath", producerOnly = true,
category = { Category.SEARCH, Category.MONITORING }, headersClass
= SolrConstants.class)
+@BodyTypes(producerIn = @BodyType(value = Carrier.ANY,
+ byOption = @BodyType.When(option =
"operation", value = "DELETE",
+ carriers = {
Carrier.TEXT, Carrier.LIST }),
+ description = "What the operation needs:
INSERT a Map or a SolrInputDocument, a List of"
+ + " them or of @Field beans, a
JSON array or XML text, or a file; DELETE the id"
+ + " or, with
deleteByQuery=true, the query, as text or a List of text; SEARCH"
+ + " the query as text or a
SolrQuery; PING does not use it. Convert bytes or a"
+ + " stream to text first. The
CamelSolrField. and CamelSolrQueryString headers"
+ + " can replace the body"),
+ producerOut = @BodyType(value = Carrier.MAP,
+ description = "The response of Solr as a
Map (a SimpleOrderedMap) with the responseHeader"
+ + " and, for a search, the
documents under response as a SolrDocumentList."
+ + " Convert it to a
QueryResponse or a SolrPingResponse to read it with"
+ + " SolrJ"))
public class SolrEndpoint extends DefaultEndpoint implements
EndpointServiceLocation {
private static final Logger LOG =
LoggerFactory.getLogger(SolrEndpoint.class);
diff --git
a/components/camel-spring-parent/camel-spring-redis/src/generated/resources/META-INF/org/apache/camel/component/redis/spring-redis.json
b/components/camel-spring-parent/camel-spring-redis/src/generated/resources/META-INF/org/apache/camel/component/redis/spring-redis.json
index d6b8fc72d591..4af7413f7668 100644
---
a/components/camel-spring-parent/camel-spring-redis/src/generated/resources/META-INF/org/apache/camel/component/redis/spring-redis.json
+++
b/components/camel-spring-parent/camel-spring-redis/src/generated/resources/META-INF/org/apache/camel/component/redis/spring-redis.json
@@ -60,6 +60,11 @@
"CamelRedis.Longitude": { "index": 27, "kind": "header", "displayName":
"", "group": "common", "label": "", "required": false, "javaType": "Double",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "Longitude.", "constantName":
"org.apache.camel.component.redis.RedisConstants#LONGITUDE" },
"CamelRedis.Radius": { "index": 28, "kind": "header", "displayName": "",
"group": "common", "label": "", "required": false, "javaType": "Double",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "Radius.", "constantName":
"org.apache.camel.component.redis.RedisConstants#RADIUS" }
},
+ "bodyTypes": {
+ "consumerOut": { "carriers": [ "unknown" ], "description": "The message as
the serializer reads it: with the default JDK serializer the Java object the
publisher serialized, such as the String a PUBLISH of this component sent, with
the channel in the CamelRedis.Channel header. A message that is not Java
serialized, such as one from redis-cli, is dropped with a WARN: set a
StringRedisSerializer as the serializer to receive text" },
+ "producerIn": { "carriers": [ "any" ], "description": "The body is not
used: the key, the value and the other arguments of the command come from
headers, such as CamelRedis.Key and CamelRedis.Value, or CamelRedis.Channel and
CamelRedis.Message for PUBLISH. Set CamelRedis.Value from the body to store the
body: with the default serializer it must be Serializable, so a stream fails" },
+ "producerOut": { "carriers": [ "unchanged" ], "dependsOn": [ "command" ],
"byOption": [ { "option": "command", "value": "SET", "carriers": [ "unchanged"
] }, { "option": "command", "value": "SETEX", "carriers": [ "unchanged" ] }, {
"option": "command", "value": "MSET", "carriers": [ "unchanged" ] }, {
"option": "command", "value": "HSET", "carriers": [ "unchanged" ] }, {
"option": "command", "value": "HMSET", "carriers": [ "unchanged" ] }, {
"option": "command", "value": "HDEL", "car [...]
+ },
"properties": {
"host": { "index": 0, "kind": "path", "displayName": "Host", "group":
"common", "label": "", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.redis.RedisConfiguration", "configurationField":
"configuration", "description": "The host where Redis server is running." },
"port": { "index": 1, "kind": "path", "displayName": "Port", "group":
"common", "label": "", "required": true, "type": "integer", "javaType":
"java.lang.Integer", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.redis.RedisConfiguration", "configurationField":
"configuration", "description": "Redis server port number" },
diff --git
a/components/camel-spring-parent/camel-spring-redis/src/main/docs/spring-redis-component.adoc
b/components/camel-spring-parent/camel-spring-redis/src/main/docs/spring-redis-component.adoc
index 302c90ea9268..a9037b6057bb 100644
---
a/components/camel-spring-parent/camel-spring-redis/src/main/docs/spring-redis-component.adoc
+++
b/components/camel-spring-parent/camel-spring-redis/src/main/docs/spring-redis-component.adoc
@@ -53,7 +53,9 @@ at
https://github.com/apache/camel/tree/main/components/camel-spring-redis/src/t
The producer runs the command of the `command` option, or of the
`CamelRedis.Command` header.
The parameters of the command come from headers, such as `CamelRedis.Key` and
`CamelRedis.Value`, not from the
-message body. The tables below list the parameters of each command. The result
of the command is the message body:
+message body. The tables below list the parameters of each command. The result
of the command becomes the message body,
+and a command without a result, such as `SET`, or a result that is null, such
as `GET` of a missing key, leaves the body
+as it was:
[source,yaml]
----
@@ -156,17 +158,19 @@ these keys:
=== Message headers evaluated by the Redis producer
The producer issues commands to the server, and each command has
-a different set of parameters with specific types. The result from the
-command execution is returned in the message body.
+a different set of parameters with specific types. The result of the
+command becomes the message body. A command whose result is void, and a result
that is null, leave the body as it was.
+The value commands, such as `GET`, `HGET` and `LPOP`, return the object that
was stored: with the default serializer the
+Java object the `CamelRedis.Value` header held.
[width="100%",cols="10%,40%,50%,10%",options="header",]
|=======================================================================
|Hash Commands |Description |Parameters |Result
|`HSET` |Set the string value of a hash field
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.FIELD`/"CamelRedis.Field" (String),
`RedisConstants.VALUE`/"CamelRedis.Value"
(Object) |void
-|`HGET` |Get the value of a hash field |`RedisConstants.KEY`/"CamelRedis.Key"
(String), `RedisConstants.FIELD`/"CamelRedis.Field" (String) |String
+|`HGET` |Get the value of a hash field |`RedisConstants.KEY`/"CamelRedis.Key"
(String), `RedisConstants.FIELD`/"CamelRedis.Field" (String) |Object
|`HSETNX` |Set the value of a hash field only if the field does not exist
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.FIELD`/"CamelRedis.Field" (String),
`RedisConstants.VALUE`/"CamelRedis.Value"
-(Object) |void
+(Object) |Boolean
|`HMSET` |Set multiple hash fields to multiple values
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.VALUES`/"CamelRedis.Values" (Map<String, Object>) |void
|`HMGET` |Get the values of all the given hash fields
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.FIELDS`/"CamelRedis.Fields" (Collection<String>)
|Collection<Object>
|`HINCRBY` |Increment the integer value of a hash field by the given number
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.FIELD`/"CamelRedis.Field" (String),
`RedisConstants.VALUE`/"CamelRedis.Value"
@@ -195,7 +199,7 @@ command execution is returned in the message body.
|`LTRIM` |Trim a list to the specified range
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.START`/"CamelRedis.Start"Long),
`RedisConstants.END`/"CamelRedis.End" (Long) |void
-|`LINDEX` |Get an element from a list by its index
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.INDEX`/"CamelRedis.Index" (Long) |String
+|`LINDEX` |Get an element from a list by its index
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.INDEX`/"CamelRedis.Index" (Long) |Object
|`LINSERT` |Insert an element before or after another element in a list
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.VALUE`/"CamelRedis.Value" (Object),
`RedisConstants.PIVOT`/"CamelRedis.Pivot"
(String), `RedisConstants.POSITION`/"CamelRedis.Position" (String) |Long
@@ -208,7 +212,7 @@ command execution is returned in the message body.
|`LPOP` |Remove and get the first element in a list
|`RedisConstants.KEY`/"CamelRedis.Key" (String) |Object
-|`RPOP` |Remove and get the last element in a list
|`RedisConstants.KEY`/"CamelRedis.Key" (String) |String
+|`RPOP` |Remove and get the last element in a list
|`RedisConstants.KEY`/"CamelRedis.Key" (String) |Object
|`RPOPLPUSH` |Remove the last element in a list, append it to another list and
return
it |`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.DESTINATION`/"CamelRedis.Destination" (String) |Object
@@ -221,20 +225,20 @@ until one is available
|`RedisConstants.KEY`/"CamelRedis.Key" (String), `RedisCo
available |`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.TIMEOUT`/"CamelRedis.Timeout" (Long) |Object
|`BRPOP` |Remove and get the last element in a list, or block until one is
-available |`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.TIMEOUT`/"CamelRedis.Timeout" (Long) |String
+available |`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.TIMEOUT`/"CamelRedis.Timeout" (Long) |Object
|=======================================================================
[width="100%",cols="10%,40%,50%,10%",options="header",]
|=======================================================================
|Set Commands |Description |Parameters |Result
-|`SADD` |Add one or more members to a set
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.VALUE`/"CamelRedis.Value" (Object) |Boolean
+|`SADD` |Add one or more members to a set
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.VALUE`/"CamelRedis.Value" (Object) |Long
|`SMEMBERS` |Get all the members in a set
|`RedisConstants.KEY`/"CamelRedis.Key" (String) |Set<Object>
-|`SREM` |Remove one or more members from a set
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.VALUE`/"CamelRedis.Value" (Object) |Boolean
+|`SREM` |Remove one or more members from a set
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.VALUE`/"CamelRedis.Value" (Object) |Long
-|`SPOP` |Remove and return a random member from a set
|`RedisConstants.KEY`/"CamelRedis.Key" (String) |String
+|`SPOP` |Remove and return a random member from a set
|`RedisConstants.KEY`/"CamelRedis.Key" (String) |Object
|`SMOVE` |Move a member from one set to another
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.VALUE`/"CamelRedis.Value" (Object),
`RedisConstants.DESTINATION`/"CamelRedis.Destination" (String) |Boolean
@@ -258,7 +262,7 @@ available |`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.TIMEO
|`SDIFFSTORE` |Subtract multiple sets and store the resulting set in a key
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.KEYS`/"CamelRedis.Keys" (String),
`RedisConstants.DESTINATION`/"CamelRedis.Destination" (String) |void
-|`SRANDMEMBER` |Get one or multiple random members from a set
|`RedisConstants.KEY`/"CamelRedis.Key" (String) |String
+|`SRANDMEMBER` |Get one or multiple random members from a set
|`RedisConstants.KEY`/"CamelRedis.Key" (String) |Object
|=======================================================================
[width="100%",cols="10%,40%,50%,10%",options="header",]
@@ -272,7 +276,7 @@ already exists |`RedisConstants.KEY`/"CamelRedis.Key"
(String), `RedisConstants.
|`ZRANGE` |Return a range of members in a sorted set, by index
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.START`/"CamelRedis.Start"Long),
`RedisConstants.END`/"CamelRedis.End" (Long),
`RedisConstants.WITHSCORE`/"CamelRedis.WithScore" (Boolean) |Object
-|`ZREM` |Remove one or more members from a sorted set
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.VALUE`/"CamelRedis.Value" (Object) |Boolean
+|`ZREM` |Remove one or more members from a sorted set
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.VALUE`/"CamelRedis.Value" (Object) |Long
|`ZINCRBY` |Increment the score of a member in a sorted set
|`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.VALUE`/"CamelRedis.Value" (Object),
`RedisConstants.INCREMENT`/"CamelRedis.Increment"
(Double) |Double
@@ -362,9 +366,9 @@ new key |`RedisConstants.KEY`/"CamelRedis.Key" (String),
`RedisConstants.KEYS`/"
|`DEL` |Delete a key |`RedisConstants.KEYS`/"CamelRedis.Keys" (String) |void
-|`TYPE` |Determine the type stored at key
|`RedisConstants.KEY`/"CamelRedis.Key" (String) |DataType
+|`TYPE` |Determine the type stored at key
|`RedisConstants.KEY`/"CamelRedis.Key" (String) |String
-|`KEYS` |Find all keys matching the given pattern
|`RedisConstants.PATERN`/"CamelRedis.Pattern" (String) |Collection<String>
+|`KEYS` |Find all keys matching the given pattern
|`RedisConstants.PATERN`/"CamelRedis.Pattern" (String) |Set<String>
|`RANDOMKEY` |Return a random key from the keyspace
|`RedisConstants.PATERN`/"CamelRedis.Pattern" (String),
`RedisConstants.VALUE`/"CamelRedis.Value" (String) |String
diff --git
a/components/camel-spring-parent/camel-spring-redis/src/main/java/org/apache/camel/component/redis/RedisEndpoint.java
b/components/camel-spring-parent/camel-spring-redis/src/main/java/org/apache/camel/component/redis/RedisEndpoint.java
index fdc4049b430c..38e3afc7914a 100644
---
a/components/camel-spring-parent/camel-spring-redis/src/main/java/org/apache/camel/component/redis/RedisEndpoint.java
+++
b/components/camel-spring-parent/camel-spring-redis/src/main/java/org/apache/camel/component/redis/RedisEndpoint.java
@@ -20,6 +20,9 @@ import org.apache.camel.Category;
import org.apache.camel.Consumer;
import org.apache.camel.Processor;
import org.apache.camel.Producer;
+import org.apache.camel.spi.BodyType;
+import org.apache.camel.spi.BodyType.Carrier;
+import org.apache.camel.spi.BodyTypes;
import org.apache.camel.spi.EndpointServiceLocation;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.spi.UriParam;
@@ -31,6 +34,88 @@ import org.springframework.data.redis.core.RedisTemplate;
*/
@UriEndpoint(firstVersion = "2.11.0", scheme = "spring-redis", title = "Spring
Redis", syntax = "spring-redist:host:port",
category = { Category.CACHE }, headersClass =
RedisConstants.class)
+@BodyTypes(consumerOut = @BodyType(value = Carrier.UNKNOWN,
+ description = "The message as the
serializer reads it: with the default JDK serializer the"
+ + " Java object the publisher
serialized, such as the String a PUBLISH of this"
+ + " component sent, with the
channel in the CamelRedis.Channel header. A"
+ + " message that is not Java
serialized, such as one from redis-cli, is"
+ + " dropped with a WARN: set
a StringRedisSerializer as the serializer to"
+ + " receive text"),
+ producerIn = @BodyType(value = Carrier.ANY,
+ description = "The body is not used: the
key, the value and the other arguments of the"
+ + " command come from headers,
such as CamelRedis.Key and CamelRedis.Value, or"
+ + " CamelRedis.Channel and
CamelRedis.Message for PUBLISH. Set CamelRedis.Value"
+ + " from the body to store the
body: with the default serializer it must be"
+ + " Serializable, so a stream
fails"),
+ producerOut = @BodyType(value = Carrier.UNCHANGED, dependsOn =
"command",
+ byOption = {
+ @BodyType.When(option = "command",
value = "SET", carriers = Carrier.UNCHANGED),
+ @BodyType.When(option = "command",
value = "SETEX", carriers = Carrier.UNCHANGED),
+ @BodyType.When(option = "command",
value = "MSET", carriers = Carrier.UNCHANGED),
+ @BodyType.When(option = "command",
value = "HSET", carriers = Carrier.UNCHANGED),
+ @BodyType.When(option = "command",
value = "HMSET", carriers = Carrier.UNCHANGED),
+ @BodyType.When(option = "command",
value = "HDEL", carriers = Carrier.UNCHANGED),
+ @BodyType.When(option = "command",
value = "DEL", carriers = Carrier.UNCHANGED),
+ @BodyType.When(option = "command",
value = "PUBLISH", carriers = Carrier.UNCHANGED),
+ @BodyType.When(option = "command",
value = "LSET", carriers = Carrier.UNCHANGED),
+ @BodyType.When(option = "command",
value = "LTRIM", carriers = Carrier.UNCHANGED),
+ @BodyType.When(option = "command",
value = "RENAME", carriers = Carrier.UNCHANGED),
+ @BodyType.When(option = "command",
value = "EXISTS", carriers = Carrier.VALUE,
+ javaType =
"java.lang.Boolean"),
+ @BodyType.When(option = "command",
value = "EXPIRE", carriers = Carrier.VALUE,
+ javaType =
"java.lang.Boolean"),
+ @BodyType.When(option = "command",
value = "SETNX", carriers = Carrier.VALUE,
+ javaType =
"java.lang.Boolean"),
+ @BodyType.When(option = "command",
value = "HEXISTS", carriers = Carrier.VALUE,
+ javaType =
"java.lang.Boolean"),
+ @BodyType.When(option = "command",
value = "SISMEMBER", carriers = Carrier.VALUE,
+ javaType =
"java.lang.Boolean"),
+ @BodyType.When(option = "command",
value = "INCR", carriers = Carrier.VALUE,
+ javaType =
"java.lang.Long"),
+ @BodyType.When(option = "command",
value = "INCRBY", carriers = Carrier.VALUE,
+ javaType =
"java.lang.Long"),
+ @BodyType.When(option = "command",
value = "DECR", carriers = Carrier.VALUE,
+ javaType =
"java.lang.Long"),
+ @BodyType.When(option = "command",
value = "DECRBY", carriers = Carrier.VALUE,
+ javaType =
"java.lang.Long"),
+ @BodyType.When(option = "command",
value = "LPUSH", carriers = Carrier.VALUE,
+ javaType =
"java.lang.Long"),
+ @BodyType.When(option = "command",
value = "RPUSH", carriers = Carrier.VALUE,
+ javaType =
"java.lang.Long"),
+ @BodyType.When(option = "command",
value = "LLEN", carriers = Carrier.VALUE,
+ javaType =
"java.lang.Long"),
+ @BodyType.When(option = "command",
value = "SADD", carriers = Carrier.VALUE,
+ javaType =
"java.lang.Long"),
+ @BodyType.When(option = "command",
value = "SREM", carriers = Carrier.VALUE,
+ javaType =
"java.lang.Long"),
+ @BodyType.When(option = "command",
value = "SCARD", carriers = Carrier.VALUE,
+ javaType =
"java.lang.Long"),
+ @BodyType.When(option = "command",
value = "HLEN", carriers = Carrier.VALUE,
+ javaType =
"java.lang.Long"),
+ @BodyType.When(option = "command",
value = "TTL", carriers = Carrier.VALUE,
+ javaType =
"java.lang.Long"),
+ @BodyType.When(option = "command",
value = "PING", carriers = Carrier.TEXT,
+ javaType =
"java.lang.String"),
+ @BodyType.When(option = "command",
value = "ECHO", carriers = Carrier.TEXT,
+ javaType =
"java.lang.String"),
+ @BodyType.When(option = "command",
value = "HGETALL", carriers = Carrier.MAP),
+ @BodyType.When(option = "command",
value = "KEYS", carriers = Carrier.LIST),
+ @BodyType.When(option = "command",
value = "HKEYS", carriers = Carrier.LIST),
+ @BodyType.When(option = "command",
value = "HVALS", carriers = Carrier.LIST),
+ @BodyType.When(option = "command",
value = "SMEMBERS", carriers = Carrier.LIST),
+ @BodyType.When(option = "command",
value = "ZRANGE", carriers = Carrier.LIST),
+ @BodyType.When(option = "command",
value = "ZREVRANGE", carriers = Carrier.LIST),
+ @BodyType.When(option = "command",
value = "LRANGE", carriers = Carrier.LIST),
+ @BodyType.When(option = "command",
value = "MGET", carriers = Carrier.LIST),
+ @BodyType.When(option = "command",
value = "HMGET", carriers = Carrier.LIST) },
+ description = "The result of the command,
which the CamelRedis.Command header can pick"
+ + " instead of the command
option: SET, the default, PUBLISH and the other"
+ + " commands without a result
keep the body; a Boolean or a number for those"
+ + " that test, count or
increment, a Set or a List for those that read several"
+ + " members, a Map for
HGETALL, and the stored object, which can be anything,"
+ + " for GET, HGET, LINDEX,
LPOP, RPOP, SPOP and the other commands that read"
+ + " or pop one value: these
are not known. A null result, such as GET of a"
+ + " missing key, keeps the
body as well"))
public class RedisEndpoint extends DefaultEndpoint implements
EndpointServiceLocation {
@UriParam
diff --git
a/components/camel-ssh/src/generated/resources/META-INF/org/apache/camel/component/ssh/ssh.json
b/components/camel-ssh/src/generated/resources/META-INF/org/apache/camel/component/ssh/ssh.json
index dd1c9ac5740b..6fa65e1a1bc7 100644
---
a/components/camel-ssh/src/generated/resources/META-INF/org/apache/camel/component/ssh/ssh.json
+++
b/components/camel-ssh/src/generated/resources/META-INF/org/apache/camel/component/ssh/ssh.json
@@ -63,6 +63,11 @@
"CamelSshStderr": { "index": 2, "kind": "header", "displayName": "",
"group": "common", "label": "", "required": false, "javaType": "InputStream",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The value of this header is a InputStream with the
standard error stream of the executable.", "constantName":
"org.apache.camel.component.ssh.SshConstants#STDERR" },
"CamelSshExitValue": { "index": 3, "kind": "header", "displayName": "",
"group": "common", "label": "", "required": false, "javaType": "Integer",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "important": true, "description": "The value of this header is the exit
value that is returned, after the execution. By convention a non-zero status
exit value indicates abnormal termination. Note that the exit value is OS
dependent.", "constantName": "org.apac [...]
},
+ "bodyTypes": {
+ "consumerOut": { "carriers": [ "stream" ], "description": "The standard
output of the pollCommand as a stream, with the exit value and the standard
error in the CamelSshExitValue and CamelSshStderr headers" },
+ "producerIn": { "carriers": [ "text", "bytes", "stream", "file" ],
"description": "The command to run, as text: bytes, a stream or a file are read
as text. A Map or a POJO is sent as its toString(): build the command as text
first. No body fails" },
+ "producerOut": { "carriers": [ "stream" ], "description": "The standard
output of the command as a stream, with the exit value and the standard error
in the CamelSshExitValue and CamelSshStderr headers; an exit value that is not
0 does not fail the exchange. Convert it to text to read it more than once" }
+ },
"properties": {
"host": { "index": 0, "kind": "path", "displayName": "Host", "group":
"common", "label": "", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.ssh.SshConfiguration", "configurationField":
"configuration", "description": "Sets the hostname of the remote SSH server." },
"port": { "index": 1, "kind": "path", "displayName": "Port", "group":
"common", "label": "", "required": false, "type": "integer", "javaType": "int",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": 22,
"configurationClass": "org.apache.camel.component.ssh.SshConfiguration",
"configurationField": "configuration", "description": "Sets the port number for
the remote SSH server." },
diff --git a/components/camel-ssh/src/main/docs/ssh-component.adoc
b/components/camel-ssh/src/main/docs/ssh-component.adoc
index e1b2e38de453..79f1fabccde9 100644
--- a/components/camel-ssh/src/main/docs/ssh-component.adoc
+++ b/components/camel-ssh/src/main/docs/ssh-component.adoc
@@ -50,6 +50,10 @@ When the SSH Component is used as a Producer
(`.to("ssh://...")`), it
will send the message body as the command to execute on the remote SSH
server.
+After the call, the message body is the standard output of the command as a
stream, with the exit value in the
+`CamelSshExitValue` header and the standard error, as a stream as well, in the
`CamelSshStderr` header. An exit value
+that is not 0 does not fail the exchange. The polling consumer gives the
output of its `pollCommand` the same way.
+
Here is an example of this. Note that the command has
a newline (`+ +`).
diff --git
a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshEndpoint.java
b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshEndpoint.java
index f2f5298d821e..91874a082274 100644
---
a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshEndpoint.java
+++
b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshEndpoint.java
@@ -22,6 +22,9 @@ import org.apache.camel.Category;
import org.apache.camel.Consumer;
import org.apache.camel.Processor;
import org.apache.camel.Producer;
+import org.apache.camel.spi.BodyType;
+import org.apache.camel.spi.BodyType.Carrier;
+import org.apache.camel.spi.BodyTypes;
import org.apache.camel.spi.EndpointServiceLocation;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.spi.UriParam;
@@ -34,6 +37,18 @@ import org.apache.sshd.common.keyprovider.KeyPairProvider;
@UriEndpoint(firstVersion = "2.10.0", scheme = "ssh", title = "SSH", syntax =
"ssh:host:port",
alternativeSyntax = "ssh:username:password@host:port", category =
{ Category.FILE },
headersClass = SshConstants.class)
+@BodyTypes(consumerOut = @BodyType(value = Carrier.STREAM,
+ description = "The standard output of the
pollCommand as a stream, with the exit value and"
+ + " the standard error in the
CamelSshExitValue and CamelSshStderr headers"),
+ producerIn = @BodyType(value = { Carrier.TEXT, Carrier.BYTES,
Carrier.STREAM, Carrier.FILE },
+ description = "The command to run, as text:
bytes, a stream or a file are read as text. A Map"
+ + " or a POJO is sent as its
toString(): build the command as text first. No"
+ + " body fails"),
+ producerOut = @BodyType(value = Carrier.STREAM,
+ description = "The standard output of the
command as a stream, with the exit value and the"
+ + " standard error in the
CamelSshExitValue and CamelSshStderr headers; an"
+ + " exit value that is not 0
does not fail the exchange. Convert it to text to"
+ + " read it more than once"))
public class SshEndpoint extends ScheduledPollEndpoint implements
EndpointServiceLocation {
@UriParam
diff --git
a/components/camel-telegram/src/generated/resources/META-INF/org/apache/camel/component/telegram/telegram.json
b/components/camel-telegram/src/generated/resources/META-INF/org/apache/camel/component/telegram/telegram.json
index a26ad023217c..2c99fd226779 100644
---
a/components/camel-telegram/src/generated/resources/META-INF/org/apache/camel/component/telegram/telegram.json
+++
b/components/camel-telegram/src/generated/resources/META-INF/org/apache/camel/component/telegram/telegram.json
@@ -41,6 +41,11 @@
"CamelTelegramParseMode": { "index": 4, "kind": "header", "displayName":
"", "group": "common", "label": "", "required": false, "javaType":
"org.apache.camel.component.telegram.TelegramParseMode", "enum": [ "HTML",
"MARKDOWN" ], "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "This header is used to format text messages
using HTML or Markdown", "constantName":
"org.apache.camel.component.telegram.TelegramConstants#TELEGRAM_PARSE_MODE" },
"CamelMessageTimestamp": { "index": 5, "kind": "header", "displayName":
"", "group": "common", "label": "", "required": false, "javaType": "long",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The message timestamp.", "constantName":
"org.apache.camel.component.telegram.TelegramConstants#MESSAGE_TIMESTAMP" }
},
+ "bodyTypes": {
+ "consumerOut": { "carriers": [ "pojo", "null" ], "description": "One
message per update: an IncomingMessage for a message or a channel post, with
the chat id in the CamelTelegramChatId header, and the IncomingCallbackQuery,
IncomingInlineQuery, PreCheckoutQuery, ShippingQuery or PaidMediaPurchased of
the other updates; no body for an update of another kind, such as an edited
message" },
+ "producerIn": { "carriers": [ "text", "bytes", "stream", "file", "pojo",
"null" ], "description": "A message of
org.apache.camel.component.telegram.model, such as an OutgoingTextMessage, or
text to send as a text message: a stream or a file is read as text, and a Map
or another POJO is sent as its toString(), so marshal it first. A byte array is
sent as the photo, audio, video or document the CamelTelegramMediaType header
names, and fails without it. No body sends nothing" },
+ "producerOut": { "carriers": [ "pojo", "unchanged" ], "description": "The
MessageResult of the call, with the message sent, or a subclass of it such as
MessageResultString for createInvoiceLink; an answer with ok=false is a
MessageResult too. No body is left as it is" }
+ },
"properties": {
"type": { "index": 0, "kind": "path", "displayName": "Type", "group":
"common", "label": "", "required": true, "type": "enum", "javaType":
"java.lang.String", "enum": [ "bots" ], "deprecated": false, "deprecationNote":
"", "autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.telegram.TelegramConfiguration",
"configurationField": "configuration", "description": "The endpoint type.
Currently, only the 'bots' type is supported." },
"limit": { "index": 1, "kind": "parameter", "displayName": "Limit",
"group": "consumer", "label": "consumer", "required": false, "type": "integer",
"javaType": "java.lang.Integer", "optionalPrefix": "consumer.", "deprecated":
false, "autowired": false, "secret": false, "defaultValue": 100,
"configurationClass":
"org.apache.camel.component.telegram.TelegramConfiguration",
"configurationField": "configuration", "description": "Limit on the number of
updates that can be received in a si [...]
diff --git a/components/camel-telegram/src/main/docs/telegram-component.adoc
b/components/camel-telegram/src/main/docs/telegram-component.adoc
index 1c01a0531f03..decdf4ee0d9e 100644
--- a/components/camel-telegram/src/main/docs/telegram-component.adoc
+++ b/components/camel-telegram/src/main/docs/telegram-component.adoc
@@ -123,7 +123,7 @@ The following message bodies are allowed for a producer
endpoint (messages of ty
| `EditMessageMediaMessage` | To edit animation, audio, document, photo, or
video messages. (editMessageMedia)
| `EditMessageReplyMarkupMessage` | To edit only the reply markup of a
message. (editMessageReplyMarkup)
| `EditMessageDelete` | To delete a message, including service messages.
(deleteMessage)
-| `SendLocationMessage` | To send a location (setSendLocation)
+| `SendLocationMessage` | To send a location (sendLocation)
| `EditMessageLiveLocationMessage` | To send changes to a live location
(editMessageLiveLocation)
| `StopMessageLiveLocationMessage` | To stop updating a live location message
sent by the bot or via the bot (for inline bots) before live_period expires
(stopMessageLiveLocation)
| `SendVenueMessage` | To send information about a venue (sendVenue)
@@ -136,11 +136,15 @@ The following message bodies are allowed for a producer
endpoint (messages of ty
| `GetStarTransactionsMessage` | To get the list of bot's Telegram Star
transactions (getStarTransactions)
| `RefundStarPaymentMessage` | To refund a successful payment in Telegram
Stars (refundStarPayment)
| `EditUserStarSubscriptionMessage` | To cancel or re-enable extension of a
subscription paid in Telegram Stars (editUserStarSubscription)
-| `byte[]` | To send any media type supported. It requires the
`CamelTelegramMediaType` header to be set to the appropriate media type
+| `byte[]` | To send a photo, an audio, a video or a document, as the
`CamelTelegramMediaType` header names (`PHOTO_PNG`, `PHOTO_JPG`, `AUDIO`,
`VIDEO` or `DOCUMENT`). It fails without the header. A stream or a file is sent
as text, so convert it to `byte[]` to send it as media
| `String` | To send a text message to a chat. It gets converted automatically
into a `OutgoingTextMessage`
|===================================================
+Any other body is sent as text, so marshal a Map or another object first, as
it is otherwise sent as its `toString()`.
+After the call the message body is the `MessageResult` of the call, with the
message sent, or a subclass of it, such as
+`MessageResultString` for `CreateInvoiceLinkMessage`. A message body that is
null sends nothing, and stays null.
+
=== Consumer
@@ -204,11 +208,16 @@ Supported types for incoming messages are
|===================================================
| Java Type | Description
-| `IncomingMessage` | The full object representation of an incoming message
+| `IncomingMessage` | The full object representation of an incoming message or
channel post, with the chat id in the `CamelTelegramChatId` header
| `String` | The content of the message, for text messages only
+| `IncomingCallbackQuery` | A callback query, from a button of an inline
keyboard
+| `IncomingInlineQuery` | An inline query
+| `PreCheckoutQuery`, `ShippingQuery`, `PaidMediaPurchased` | The payment
updates, of the package `org.apache.camel.component.telegram.model.payments`
|===================================================
+An update of another kind, such as an edited message, gives a message with no
body.
+
=== Reactive Chat-Bot Example
diff --git
a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramEndpoint.java
b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramEndpoint.java
index f1f248bb383e..d13603036b7b 100644
---
a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramEndpoint.java
+++
b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramEndpoint.java
@@ -38,6 +38,9 @@ import org.apache.camel.RuntimeCamelException;
import
org.apache.camel.component.telegram.service.TelegramServiceRestBotAPIAdapter;
import org.apache.camel.component.webhook.WebhookCapableEndpoint;
import org.apache.camel.component.webhook.WebhookConfiguration;
+import org.apache.camel.spi.BodyType;
+import org.apache.camel.spi.BodyType.Carrier;
+import org.apache.camel.spi.BodyTypes;
import org.apache.camel.spi.EndpointServiceLocation;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.spi.UriParam;
@@ -51,6 +54,25 @@ import org.slf4j.LoggerFactory;
*/
@UriEndpoint(firstVersion = "2.18.0", scheme = "telegram", title = "Telegram",
syntax = "telegram:type",
category = { Category.CLOUD, Category.API, Category.CHAT },
headersClass = TelegramConstants.class)
+@BodyTypes(consumerOut = @BodyType(value = { Carrier.POJO, Carrier.NULL },
+ description = "One message per update: an
IncomingMessage for a message or a channel post,"
+ + " with the chat id in the
CamelTelegramChatId header, and the"
+ + " IncomingCallbackQuery,
IncomingInlineQuery, PreCheckoutQuery,"
+ + " ShippingQuery or
PaidMediaPurchased of the other updates; no body for an"
+ + " update of another kind,
such as an edited message"),
+ producerIn = @BodyType(value = {
+ Carrier.TEXT, Carrier.BYTES, Carrier.STREAM, Carrier.FILE,
Carrier.POJO,
+ Carrier.NULL },
+ description = "A message of
org.apache.camel.component.telegram.model, such as an"
+ + " OutgoingTextMessage, or
text to send as a text message: a stream or a file"
+ + " is read as text, and a Map
or another POJO is sent as its toString(), so"
+ + " marshal it first. A byte
array is sent as the photo, audio, video or"
+ + " document the
CamelTelegramMediaType header names, and fails without it."
+ + " No body sends nothing"),
+ producerOut = @BodyType(value = { Carrier.POJO, Carrier.UNCHANGED },
+ description = "The MessageResult of the
call, with the message sent, or a subclass of it"
+ + " such as
MessageResultString for createInvoiceLink; an answer with ok=false"
+ + " is a MessageResult too.
No body is left as it is"))
public class TelegramEndpoint extends ScheduledPollEndpoint implements
WebhookCapableEndpoint, EndpointServiceLocation {
private static final Logger LOG =
LoggerFactory.getLogger(TelegramEndpoint.class);
private static final Pattern WEBHOOK_SECRET_TOKEN_PATTERN =
Pattern.compile("[A-Za-z0-9_-]{1,256}");
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/CatalogBodyTypes.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/CatalogBodyTypes.java
index def082d4063b..16dad51ecaa9 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/CatalogBodyTypes.java
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/CatalogBodyTypes.java
@@ -35,6 +35,7 @@ import
org.apache.camel.tooling.model.BodyTypeModel.OptionBodyTypeModel;
import org.apache.camel.tooling.model.ComponentModel;
import org.apache.camel.tooling.model.DataFormatModel;
import org.apache.camel.tooling.model.EipModel;
+import org.apache.camel.util.StringHelper;
import static org.apache.camel.dsl.yaml.validator.RouteGraph.scheme;
@@ -252,7 +253,7 @@ final class CatalogBodyTypes {
for (String option : side.getDependsOn()) {
String value = set.get(option);
if (value != null && side.getByOption().stream()
- .noneMatch(w -> w.getOption().equals(option) &&
value.equalsIgnoreCase(w.getValue()))) {
+ .noneMatch(w -> w.getOption().equals(option) &&
isSameValue(value, w.getValue()))) {
// the body depends on this option, and no option value of the
side says the body for its value: the
// value another option names does not hold then, such as
output=bytes with a resultHandlerFactory
return null;
@@ -261,7 +262,7 @@ final class CatalogBodyTypes {
Answer matched = null;
for (OptionBodyTypeModel when : side.getByOption()) {
String value = set.get(when.getOption());
- if (value != null && value.equalsIgnoreCase(when.getValue())) {
+ if (value != null && isSameValue(value, when.getValue())) {
if (matched != null &&
!matched.carriers().equals(when.getCarriers())) {
// two options the step sets say different bodies
return null;
@@ -278,6 +279,15 @@ final class CatalogBodyTypes {
return new Answer(side.getCarriers(), side.getJavaType(),
side.getFormat());
}
+ /**
+ * Whether the value a step sets is the value of an option body: in any
case, and in any style of an enum constant,
+ * as the catalog and the enum type converter take it, so
operation=convert-to-json is CONVERT_TO_JSON.
+ */
+ private static boolean isSameValue(String value, String other) {
+ return value.equalsIgnoreCase(other)
+ ||
StringHelper.asEnumConstantValue(value).equals(StringHelper.asEnumConstantValue(other));
+ }
+
/** The options of a node, by name in camel case: allowNullBody as well
for allow-null-body. */
private static Map<String, String> values(JsonNode node) {
Map<String, String> answer = new HashMap<>();
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/TextBodyFlowTest.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/TextBodyFlowTest.java
index 24da4237401c..10be33f10128 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/TextBodyFlowTest.java
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/TextBodyFlowTest.java
@@ -1491,6 +1491,156 @@ public class TextBodyFlowTest {
.contains("route mail: to: smtp needs the body as
text, bytes, a stream or a file"));
}
+ @Test
+ public void testTheBodyOfMoreComponents() {
+ // ssh runs the body as a command and gives its output as a stream,
and so does its consumer; spring-redis keeps
+ // the body for SET, its default command, gives text for PING and is
not known for GET; a couchbase row read with
+ // fullDocument=false is JSON text, and so is the result of CCB_DEL,
while CCB_GET gives the GetResult of the SDK;
+ // the response of solr is a Map, and slack also sends an object as
its text
+ String yaml = """
+ - route:
+ id: shell
+ from:
+ uri: timer:tick
+ steps:
+ - setBody:
+ constant: '{"id": 1}'
+ - unmarshal:
+ json: {}
+ - to: ssh:localhost:22
+ - route:
+ id: output
+ from:
+ uri: ssh:localhost:22?pollCommand=date
+ steps:
+ - setHeader:
+ name: id
+ simple: ${body[id]}
+ - route:
+ id: ping
+ from:
+ uri: timer:tick
+ steps:
+ - to: spring-redis:localhost:6379?command=PING
+ - setHeader:
+ name: id
+ simple: ${body[id]}
+ - route:
+ id: cache
+ from:
+ uri: timer:tick
+ steps:
+ - setBody:
+ constant: '{"id": 1}'
+ - unmarshal:
+ json: {}
+ - to: spring-redis:localhost:6379
+ - setHeader:
+ name: id
+ simple: ${body[id]}
+ - route:
+ id: lookup
+ from:
+ uri: timer:tick
+ steps:
+ - to: spring-redis:localhost:6379?command=GET
+ - setHeader:
+ name: id
+ simple: ${body[id]}
+ - route:
+ id: rows
+ from:
+ uri:
couchbase:http://localhost?bucket=orders&fullDocument=false
+ steps:
+ - setHeader:
+ name: id
+ simple: ${body[id]}
+ - route:
+ id: remove
+ from:
+ uri: timer:tick
+ steps:
+ - to:
couchbase:http://localhost?bucket=orders&operation=CCB_DEL
+ - setHeader:
+ name: id
+ simple: ${body[id]}
+ - route:
+ id: fetch
+ from:
+ uri: timer:tick
+ steps:
+ - to:
couchbase:http://localhost?bucket=orders&operation=CCB_GET
+ - setHeader:
+ name: id
+ simple: ${body[id]}
+ - route:
+ id: search
+ from:
+ uri: timer:tick
+ steps:
+ - setBody:
+ constant: "id:1"
+ - to:
solr:localhost:8983/solr?collection=orders&operation=SEARCH
+ - setHeader:
+ name: hits
+ simple: ${body[response]}
+ - route:
+ id: chat
+ from:
+ uri: timer:tick
+ steps:
+ - setBody:
+ constant: '{"id": 1}'
+ - unmarshal:
+ json: {}
+ - to: slack:#orders
+ """;
+ assertThat(lines(yaml)).hasSize(5)
+ .anySatisfy(
+ m -> assertThat(m).contains("route shell: to: ssh
needs the body as text, bytes, a stream or a file"))
+ .anySatisfy(m -> assertThat(m).contains("route remove: simple
reads a field of the body (${body[id]})"))
+ .anySatisfy(m -> assertThat(m).contains("route output: simple
reads a field of the body (${body[id]})"))
+ .anySatisfy(m -> assertThat(m).contains("route ping: simple
reads a field of the body (${body[id]})"))
+ .anySatisfy(m -> assertThat(m).contains("route rows: simple
reads a field of the body (${body[id]})"));
+ }
+
+ @Test
+ public void testAnOptionValueInAnotherStyleOfTheEnum() {
+ // the catalog and the enum type converter take convert-to-json and
convertToJson as CONVERT_TO_JSON, so after
+ // docling the body is the document of that operation, and not the
text of the default operation
+ String yaml = """
+ - route:
+ id: dashes
+ from:
+ uri: timer:tick
+ steps:
+ - to: docling:convert?operation=convert-to-json
+ - setHeader:
+ name: title
+ simple: ${body[title]}
+ - route:
+ id: camelCase
+ from:
+ uri: timer:tick
+ steps:
+ - to: docling:convert?operation=convertToJson
+ - setHeader:
+ name: title
+ simple: ${body[title]}
+ - route:
+ id: markdown
+ from:
+ uri: timer:tick
+ steps:
+ - to: docling:convert?operation=convert-to-markdown
+ - setHeader:
+ name: title
+ simple: ${body[title]}
+ """;
+ assertThat(lines(yaml)).singleElement().asString()
+ .contains("route markdown: simple reads a field of the body
(${body[title]})");
+ }
+
@Test
public void testTheBodyOfCoreComponents() {
// the stream consumer gives each line as text, so a field read needs
an unmarshal, and stream:out writes text,
diff --git
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/BodyTypesHelper.java
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/BodyTypesHelper.java
index fdde7315fe11..9cab8c34ffc9 100644
---
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/BodyTypesHelper.java
+++
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/BodyTypesHelper.java
@@ -21,6 +21,7 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Set;
@@ -31,6 +32,7 @@ import org.apache.camel.tooling.model.BaseModel;
import org.apache.camel.tooling.model.BaseOptionModel;
import org.apache.camel.tooling.model.BodyTypeModel;
import org.apache.camel.tooling.model.ComponentModel;
+import org.apache.camel.tooling.util.Strings;
/**
* Carries the {@link BodyTypes} of a component, data format or language into
its model, which the catalog JSON is
@@ -140,19 +142,32 @@ final class BodyTypesHelper {
/**
* A body for a value the option cannot have would never hold: the value
is one of an enum, or true or false for a
- * boolean, in any case, as tooling compares it with what the endpoint
sets.
+ * boolean, in any case and in any style of an enum constant, as tooling
compares it with what the endpoint sets.
*/
private static void checkValue(Class<?> owner, String side, BodyType.When
when, BaseOptionModel option) {
List<String> values = option.getEnums() != null &&
!option.getEnums().isEmpty()
? option.getEnums()
: "boolean".equals(option.getType()) ? List.of("true",
"false") : List.of();
- if (!values.isEmpty() && values.stream().noneMatch(v ->
v.equalsIgnoreCase(when.value()))) {
+ if (!values.isEmpty() && values.stream().noneMatch(v -> isSameValue(v,
when.value()))) {
throw new IllegalArgumentException(
owner.getName() + ": the @BodyTypes " + side + " has " +
when.option() + "=" + when.value()
+ ", which is not a value of
the option: " + String.join(", ", values));
}
}
+ /**
+ * Whether two values of an option are one value as Camel takes it: in any
case, and in any style of an enum
+ * constant, so convert-to-json and convertToJson are CONVERT_TO_JSON, as
for the catalog and the enum type
+ * converter (StringHelper.asEnumConstantValue in camel-util, which this
plugin does not depend on).
+ */
+ private static boolean isSameValue(String value, String other) {
+ return value.equalsIgnoreCase(other) ||
asEnumConstant(value).equals(asEnumConstant(other));
+ }
+
+ private static String asEnumConstant(String value) {
+ return Strings.camelCaseToDash(value).replaceAll("-+",
"-").replace('-', '_').toUpperCase(Locale.ENGLISH);
+ }
+
/**
* A body has a carrier: an option value without one would say nothing.
UNCHANGED is for the body after a step, such
* as a sql query that leaves it unchanged unless it is a select. ANY is
for the bodies a step needs, and UNKNOWN
diff --git
a/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojoTest.java
b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojoTest.java
index fc5e64ec4ade..e135f7a465b6 100644
---
a/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojoTest.java
+++
b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojoTest.java
@@ -28,6 +28,7 @@ import
org.apache.camel.maven.packaging.endpoint.SomeEndpointUsingInterfaceConst
import org.apache.camel.maven.packaging.endpoint.SomeEndpointWithBadBodyTypes;
import org.apache.camel.maven.packaging.endpoint.SomeEndpointWithBadHeaders;
import org.apache.camel.maven.packaging.endpoint.SomeEndpointWithBodyTypes;
+import
org.apache.camel.maven.packaging.endpoint.SomeEndpointWithEnumStyleBodyTypes;
import org.apache.camel.maven.packaging.endpoint.SomeEndpointWithFilter;
import
org.apache.camel.maven.packaging.endpoint.SomeEndpointWithHeaderClassHierarchy;
import
org.apache.camel.maven.packaging.endpoint.SomeEndpointWithHeaderInterfaceHierarchy;
@@ -261,6 +262,17 @@ class EndpointSchemaGeneratorMojoTest {
assertEquals("byte[]", bytes.getJavaType());
}
+ @Test
+ void testEndpointWithBodyTypesForEnumValuesInOtherStyles() throws
Exception {
+ // the catalog and the enum type converter take convert-to-json and
chunkHybrid as CONVERT_TO_JSON and
+ // CHUNK_HYBRID, so the build takes them too
+ addEnumOption("operation", "CONVERT_TO_MARKDOWN", "CONVERT_TO_JSON",
"CHUNK_HYBRID");
+ mojo.addBodyTypes(model, SomeEndpointWithEnumStyleBodyTypes.class);
+ List<BodyTypeModel.OptionBodyTypeModel> values =
model.getBodyType(BodyTypeModel.PRODUCER_OUT).getByOption();
+ assertEquals(List.of("convert-to-json", "chunkHybrid"),
+
values.stream().map(BodyTypeModel.OptionBodyTypeModel::getValue).toList());
+ }
+
@Test
void testEndpointDoesNotInheritBodyTypes() throws Exception {
// a subclass may change the body, so it declares its own
diff --git
a/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/SomeEndpointWithEnumStyleBodyTypes.java
b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/SomeEndpointWithEnumStyleBodyTypes.java
new file mode 100644
index 000000000000..c55cd38e1a97
--- /dev/null
+++
b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/SomeEndpointWithEnumStyleBodyTypes.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.maven.packaging.endpoint;
+
+import org.apache.camel.spi.BodyType;
+import org.apache.camel.spi.BodyType.Carrier;
+import org.apache.camel.spi.BodyTypes;
+import org.apache.camel.spi.UriEndpoint;
+
+/**
+ * Body types for option values written in other styles of the enum constants
of the option.
+ */
+@UriEndpoint(scheme = "some", syntax = "some", title = "some")
+@BodyTypes(producerOut = @BodyType(value = Carrier.TEXT,
+ byOption = {
+ @BodyType.When(option =
"operation", value = "convert-to-json",
+ carriers =
Carrier.POJO),
+ @BodyType.When(option =
"operation", value = "chunkHybrid",
+ carriers =
Carrier.LIST) }))
+public class SomeEndpointWithEnumStyleBodyTypes {
+}