diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/atmosphere-websocket.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/atmosphere-websocket.json index 4bf301ec752a2..c5200281fada9 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/atmosphere-websocket.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/atmosphere-websocket.json @@ -45,6 +45,11 @@ "CamelAtmosphereWebsocketEventType": { "index": 2, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "important": true, "description": "The type of event received. It can be ONOPEN_EVENT_TYPE, ONERROR_EVENT_TYPE or ONCLOSE_EVENT_TYPE.", "constantName": "org.apache.camel.component.atmosphere.websocket.WebsocketConstants#EVENT_TYPE" }, "CamelAtmosphereWebsocketErrorType": { "index": 3, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The type of error that occurred. It can be MESSAGE_NOT_SENT_ERROR_TYPE.", "constantName": "org.apache.camel.component.atmosphere.websocket.WebsocketConstants#ERROR_TYPE" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "text", "bytes", "null" ], "byOption": [ { "option": "useStreaming", "value": "true", "carriers": [ "stream", "null" ] } ], "description": "A String for a text message, a byte array for a binary one; null for the open, close and error events (the servlet init parameter events=true). A message the producer could not deliver comes back with the CamelAtmosphereWebsocketErrorType header. The consumer does not reply" }, + "producerIn": { "carriers": [ "null", "text", "bytes", "stream" ], "description": "Text or a Reader as a text message, bytes or an InputStream as a binary one; other bodies as their toString. No body sends nothing. Sent to all peers with sendToAll, otherwise to the connection key headers" }, + "producerOut": { "carriers": [ "unchanged" ], "description": "The body is kept" } + }, "properties": { "servicePath": { "index": 0, "kind": "path", "displayName": "Service Path", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Name of websocket endpoint" }, "chunked": { "index": 1, "kind": "parameter", "displayName": "Chunked", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "If this option is false the Servlet will disable the HTTP streaming and set the content-length header on the response" }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/cxf.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/cxf.json index 578d46bed3144..d757fadf9c2a9 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/cxf.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/cxf.json @@ -41,6 +41,12 @@ "CamelAuthentication": { "index": 4, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "javax.security.auth.Subject", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The authentication", "constantName": "org.apache.camel.component.cxf.common.message.CxfConstants#AUTHENTICATION" }, "RequestContext": { "index": 5, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Object", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The request context", "constantName": "org.apache.camel.component.cxf.common.message.CxfConstants#REQUEST_CONTEXT" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "list", "null" ], "byOption": [ { "option": "dataFormat", "value": "PAYLOAD", "carriers": [ "pojo" ], "javaType": "org.apache.camel.component.cxf.common.CxfPayload" }, { "option": "dataFormat", "value": "RAW", "carriers": [ "stream" ] }, { "option": "dataFormat", "value": "MESSAGE", "carriers": [ "stream" ] }, { "option": "dataFormat", "value": "CXF_MESSAGE", "carriers": [ "pojo" ], "javaType": "jakarta.xml.soap.SOAPMessage" } ], "description": "POJO: a MessageContentsList of the parameters of the operation, typed as the service class declares them, with its name in the CamelCxfOperationName header; null for an operation without parameters. PAYLOAD: a CxfPayload of the elements of the soap:Body and the SOAP headers. RAW: the stream of the whole SOAP envelope, without the operation name. CXF_MESSAGE: the SAAJ SOAPMessage" }, + "consumerReply": { "carriers": [ "text", "value", "pojo", "list", "null" ], "byOption": [ { "option": "dataFormat", "value": "PAYLOAD", "carriers": [ "pojo", "text", "bytes", "stream", "null" ] }, { "option": "dataFormat", "value": "RAW", "carriers": [ "text", "bytes", "stream", "file", "null" ] }, { "option": "dataFormat", "value": "MESSAGE", "carriers": [ "text", "bytes", "stream", "file", "null" ] }, { "option": "dataFormat", "value": "CXF_MESSAGE", "carriers": [ "pojo" ] } ], "description": "POJO: the return value of the operation, of the type the service class declares, or a List or array of it and the out and holder parameters; another type is a SOAP fault, so the request MessageContentsList only fits an echo. PAYLOAD: a CxfPayload, or the XML of the soap:Body contents as text, bytes, a stream or a DOM; a body that does not convert sends an empty soap:Body. RAW: the whole SOAP envelope as text, bytes, a stream or a file. CXF_MESSAGE: a SOAPMessage or a javax.xml.transform Source; text or a stream sends an empty envelope" }, + "producerIn": { "carriers": [ "list", "text", "value", "pojo", "null" ], "byOption": [ { "option": "dataFormat", "value": "PAYLOAD", "carriers": [ "pojo", "text", "bytes", "stream", "file" ] }, { "option": "dataFormat", "value": "RAW", "carriers": [ "text", "bytes", "stream", "file" ] }, { "option": "dataFormat", "value": "MESSAGE", "carriers": [ "text", "bytes", "stream", "file" ] }, { "option": "dataFormat", "value": "CXF_MESSAGE", "carriers": [ "pojo" ] } ], "description": "POJO: the parameters of the operation (the CamelCxfOperationName header or defaultOperationName) as a List or an array, or the one parameter as the body; each of the type the service class declares. A body that is not a List is split like the split EIP does, so text with a comma or a byte array is several parameters: wrap it in a List. PAYLOAD: a CxfPayload, or the XML of the soap:Body contents as text, bytes, a stream, a file or a DOM. RAW: the whole SOAP envelope. CXF_MESSAGE: a SOAPMessage or a javax.xml.transform Source" }, + "producerOut": { "carriers": [ "list", "null", "unchanged" ], "byOption": [ { "option": "dataFormat", "value": "PAYLOAD", "carriers": [ "pojo" ], "javaType": "org.apache.camel.component.cxf.common.CxfPayload" }, { "option": "dataFormat", "value": "RAW", "carriers": [ "stream" ] }, { "option": "dataFormat", "value": "MESSAGE", "carriers": [ "stream" ] }, { "option": "dataFormat", "value": "CXF_MESSAGE", "carriers": [ "pojo" ], "javaType": "jakarta.xml.soap.SOAPMessage" } ], "description": "POJO: a MessageContentsList with the return value of the operation first, then the out and holder parameters; null for a void operation, and the body unchanged for a one-way one. PAYLOAD: a CxfPayload of the soap:Body contents. RAW: the stream of the SOAP envelope of the response, read once. CXF_MESSAGE: the SAAJ SOAPMessage" } + }, "properties": { "beanId": { "index": 0, "kind": "path", "displayName": "Bean Id", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "To lookup an existing configured CxfEndpoint. Must used bean: as prefix." }, "address": { "index": 1, "kind": "path", "displayName": "Address", "group": "service", "label": "service", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The service publish address." }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/cxfrs.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/cxfrs.json index d075d9619913b..abaef59b426f8 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/cxfrs.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/cxfrs.json @@ -50,6 +50,12 @@ "CamelCxfRsQueryMap": { "index": 14, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Map", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The query map", "constantName": "org.apache.camel.component.cxf.common.message.CxfConstants#CAMEL_CXF_RS_QUERY_MAP" }, "CamelCxfRsOperationResourceInfoStack": { "index": 15, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "org.apache.cxf.jaxrs.model.OperationResourceInfoStack", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The stack of MethodInvocationInfo representing resources path when JAX-RS invocation looks for target.", "constantName": "org.apache.camel.component.cxf.common.message.CxfConstants#CAMEL_CXF_RS_OPERATION_RESOURCE_INFO_STACK" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "list" ], "javaType": "org.apache.cxf.message.MessageContentsList", "dependsOn": [ "performInvocation" ], "byOption": [ { "option": "bindingStyle", "value": "SimpleConsumer", "carriers": [ "unknown" ] }, { "option": "bindingStyle", "value": "Custom", "carriers": [ "unknown" ] } ], "description": "Default: a MessageContentsList of the parameters of the resource method, with its name in the CamelCxfOperationName header. SimpleConsumer: the request entity as the method declares it (a String, an InputStream, a JAXB bean), with the path, query and header parameters in headers; the MessageContentsList when the method has no entity, such as a GET" }, + "consumerReply": { "carriers": [ "null", "text", "bytes", "stream", "file", "pojo" ], "byOption": [ { "option": "bindingStyle", "value": "Custom", "carriers": [ "any" ] } ], "description": "The response entity: a jakarta.ws.rs.core.Response, or text, bytes, a stream, a file, or an object a JAX-RS provider writes for the Content-Type (a JAXB bean as XML); a Map or a List fails without a provider for it. With the Default binding the request MessageContentsList fails: set the reply body" }, + "producerIn": { "carriers": [ "null", "text", "bytes", "stream", "file", "pojo" ], "byOption": [ { "option": "httpClientAPI", "value": "false", "carriers": [ "list", "text", "value", "pojo", "null" ] } ], "description": "The request entity, written for the Content-Type header: text, bytes, a stream, a file or an object a JAX-RS provider writes; of a List only the first element is sent, and a Map fails. A GET sends no body. With httpClientAPI=false: the parameters of the resource method named by the CamelCxfOperationName header, as a List or the one parameter" }, + "producerOut": { "carriers": [ "pojo" ], "byOption": [ { "option": "httpClientAPI", "value": "false", "carriers": [ "unknown" ] } ], "description": "A jakarta.ws.rs.core.Response whose entity is the response stream, read once (it converts to a String or an InputStream); the entity read as the class in the CamelCxfRsResponseClass header when that is set. With httpClientAPI=false: the return value of the resource method, null for a void one" } + }, "properties": { "beanId": { "index": 0, "kind": "path", "displayName": "Bean Id", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "To lookup an existing configured CxfRsEndpoint. Must used bean: as prefix." }, "address": { "index": 1, "kind": "path", "displayName": "Address", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The service publish address." }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/jetty.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/jetty.json index ea731d7618ccf..5e71ffa203626 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/jetty.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/jetty.json @@ -69,6 +69,10 @@ "CamelServletContextPath": { "index": 0, "kind": "header", "displayName": "", "group": "consumer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The servlet context path used", "constantName": "org.apache.camel.component.jetty.JettyHttpConstants#SERVLET_CONTEXT_PATH" }, "CamelHttpPath": { "index": 1, "kind": "header", "displayName": "", "group": "consumer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Request URI's path, the header will be used to build the request URI with the HTTP_URI.", "constantName": "org.apache.camel.component.jetty.JettyHttpConstants#HTTP_PATH" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "stream", "null" ], "dependsOn": [ "transferException", "httpBinding" ], "description": "The request body as a stream cache, which can be read again (the raw stream, read once, with disableStreamCache); an empty one for a GET, null with Content-Length 0 or eagerCheckContentAvailable. The fields of a form are also headers; a multipart upload leaves the body empty and gives its files as attachments and DataHandler headers" }, + "consumerReply": { "carriers": [ "null", "text", "bytes", "stream", "file" ], "description": "The response body: text, bytes, a stream or a file. A Map, a List or a POJO is sent as an empty body (as its toString with chunked=false): marshal it first" } + }, "properties": { "httpUri": { "index": 0, "kind": "path", "displayName": "Http Uri", "group": "common", "label": "common", "required": true, "type": "string", "javaType": "java.net.URI", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The url of the HTTP endpoint to call." }, "headerFilterStrategy": { "index": 1, "kind": "parameter", "displayName": "Header Filter Strategy", "group": "common (advanced)", "label": "common,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "To use a custom HeaderFilterStrategy to filter header to and from Camel message." }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/netty-http.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/netty-http.json index fced770f492c3..226aa49cc714b 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/netty-http.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/netty-http.json @@ -131,6 +131,12 @@ "CamelNettyRequestTimeout": { "index": 22, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The read timeout.", "constantName": "org.apache.camel.component.netty.NettyConstants#NETTY_REQUEST_TIMEOUT" }, "CamelNettyChannel": { "index": 23, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "io.netty.channel.Channel", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The Netty Channel object.", "constantName": "org.apache.camel.component.netty.NettyConstants#NETTY_CHANNEL" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "stream" ], "javaType": "org.apache.camel.component.netty.http.NettyChannelBufferStreamCache", "dependsOn": [ "nettyHttpBinding" ], "byOption": [ { "option": "disableStreamCache", "value": "true", "carriers": [ "pojo", "stream" ] }, { "option": "protocol", "value": "proxy", "carriers": [ "pojo" ], "javaType": "io.netty.buffer.ByteBuf" } ], "description": "The request body as the stream cache of Camel, which can be read many times; empty for a request without a body, such as a GET. The fields of a form POST are also headers. With disableStreamCache the Netty ByteBuf of the request, or an InputStream for a chunked request, read once" }, + "consumerReply": { "carriers": [ "null", "text", "bytes", "stream", "file", "value" ], "description": "The response body: text, bytes, a stream, a file, or a Netty ByteBuf or HttpResponse; no body sends 204. A Map or a POJO is written as its toString() and a List is not written at all: marshal it first. A failed exchange sends 500 with an empty body (muteException)" }, + "producerIn": { "carriers": [ "null", "text", "bytes", "stream", "file" ], "description": "The request body: text, bytes, a stream or a file, or a Netty ByteBuf or HttpRequest. A Map, a List or a POJO fails: marshal it first. Without the CamelHttpMethod header, no body sends a GET and a body a POST" }, + "producerOut": { "carriers": [ "bytes" ], "javaType": "byte[]", "dependsOn": [ "nettyHttpBinding", "sync" ], "byOption": [ { "option": "disableStreamCache", "value": "true", "carriers": [ "pojo", "stream" ] } ], "description": "The response body as a byte array, empty for a response without a body. With disableStreamCache the Netty ByteBuf of the response, or an InputStream for a chunked response; the ByteBuf is released when the exchange is done" } + }, "properties": { "protocol": { "index": 0, "kind": "path", "displayName": "Protocol", "group": "common", "label": "", "required": true, "type": "enum", "javaType": "java.lang.String", "enum": [ "http", "https", "proxy" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.netty.http.NettyHttpConfiguration", "configurationField": "configuration", "description": "The protocol to use which is either http, https or proxy (consumer only)." }, "host": { "index": 1, "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.netty.http.NettyHttpConfiguration", "configurationField": "configuration", "description": "The local hostname such as localhost, or 0.0.0.0 when being a consumer. The remote HTTP server hostname when using producer." }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/netty.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/netty.json index a0a9ceba26e62..8212556f4fa25 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/netty.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/netty.json @@ -115,6 +115,12 @@ "CamelNettyRequestTimeout": { "index": 10, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The read timeout.", "constantName": "org.apache.camel.component.netty.NettyConstants#NETTY_REQUEST_TIMEOUT" }, "CamelNettyChannel": { "index": 11, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "io.netty.channel.Channel", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The Netty Channel object.", "constantName": "org.apache.camel.component.netty.NettyConstants#NETTY_CHANNEL" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "text" ], "javaType": "java.lang.String", "dependsOn": [ "encoders", "decoders", "transferExchange" ], "byOption": [ { "option": "udpByteArrayCodec", "value": "true", "carriers": [ "bytes" ], "javaType": "byte[]" }, { "option": "allowDefaultCodec", "value": "false", "carriers": [ "pojo" ], "javaType": "io.netty.buffer.ByteBuf" } ], "description": "The data received as a String in the encoding (UTF-8 by default). Over TCP the default codec has no framing, so a message may arrive split over several exchanges; textline=true gives one line per exchange" }, + "consumerReply": { "carriers": [ "null", "text" ], "dependsOn": [ "encoders", "decoders", "transferExchange" ], "byOption": [ { "option": "textline", "value": "true", "carriers": [ "any" ] }, { "option": "udpByteArrayCodec", "value": "true", "carriers": [ "null", "bytes" ] }, { "option": "allowDefaultCodec", "value": "false", "carriers": [ "null", "pojo" ], "javaType": "io.netty.buffer.ByteBuf" } ], "description": "With sync=true (the default) the body the route ends with is written back: a String or a Netty ByteBuf. Bytes, a stream, a Map or a POJO cannot be written and the caller gets no reply: convert it to a String first (textline=true converts any body to a line of text). No body sends nothing and closes the connection (disconnectOnNoReply)" }, + "producerIn": { "carriers": [ "null", "text" ], "dependsOn": [ "encoders", "decoders", "transferExchange" ], "byOption": [ { "option": "textline", "value": "true", "carriers": [ "any" ] }, { "option": "udpByteArrayCodec", "value": "true", "carriers": [ "null", "bytes" ] }, { "option": "useByteBuf", "value": "true", "carriers": [ "null", "text", "bytes", "stream" ] }, { "option": "allowDefaultCodec", "value": "false", "carriers": [ "null", "pojo" ], "javaType": "io.netty.buffer.ByteBuf" } ], "description": "The data to send: a String, or a Netty ByteBuf over TCP. Bytes, a stream, a file, a Map or a POJO fail with an unsupported message type: convert it to a String first, or use textline=true, which converts any body to a line of text. No body sends nothing" }, + "producerOut": { "carriers": [ "text", "null" ], "javaType": "java.lang.String", "dependsOn": [ "encoders", "decoders", "transferExchange" ], "byOption": [ { "option": "sync", "value": "false", "carriers": [ "unchanged" ] }, { "option": "udpByteArrayCodec", "value": "true", "carriers": [ "bytes", "null" ], "javaType": "byte[]" }, { "option": "allowDefaultCodec", "value": "false", "carriers": [ "pojo", "null" ], "javaType": "io.netty.buffer.ByteBuf" } ], "description": "With sync=true (the default) the reply of the server as a String: over TCP without textline, the data of the first read. No body is not sent and stays null" } + }, "properties": { "protocol": { "index": 0, "kind": "path", "displayName": "Protocol", "group": "common", "label": "", "required": true, "type": "enum", "javaType": "java.lang.String", "enum": [ "tcp", "udp" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.netty.NettyConfiguration", "configurationField": "configuration", "description": "The protocol to use which can be tcp or udp" }, "host": { "index": 1, "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.netty.NettyConfiguration", "configurationField": "configuration", "description": "The hostname. For the consumer the hostname is localhost or 0.0.0.0. For the producer the hostname is the remote host to connect to." }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/rest-postman.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/rest-postman.json index 22163e396f2d0..0738544a8514e 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/rest-postman.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/rest-postman.json @@ -65,6 +65,12 @@ "CamelRestPostmanRequestCount": { "index": 3, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The number of requests executed when running a folder or a whole collection.", "constantName": "org.apache.camel.component.rest.postman.RestPostmanConstants#REQUEST_COUNT" }, "CamelRestPostmanFailedCount": { "index": 4, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The number of requests that failed when running a folder or a whole collection with runFailFast disabled.", "constantName": "org.apache.camel.component.rest.postman.RestPostmanConstants#FAILED_COUNT" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "stream", "bytes", "null", "map", "file" ], "dependsOn": [ "consumerComponentName" ], "description": "The request body as the HTTP consumer gives it (platform-http by default), null for a request without a body. It is handed to the direct route of the matched request (direct:); the route of this endpoint then has the body that route left, or the saved example as a String with missingRequest=mock" }, + "consumerReply": { "carriers": [ "null", "text", "bytes", "stream" ], "dependsOn": [ "consumerComponentName" ], "description": "The response body as the HTTP consumer writes it: text, bytes, a stream or no body. A Map or a List fails: marshal it first" }, + "producerIn": { "carriers": [ "null", "text", "bytes", "stream", "file" ], "dependsOn": [ "componentName" ], "description": "For a single request, the body sent, by the http component by default: text, bytes, a stream or a file. A Map, a List or a number fails: marshal it first. A folder or the whole collection (no requestId) sends the bodies written in the collection and ignores the message body" }, + "producerOut": { "carriers": [ "stream", "bytes", "null", "list" ], "dependsOn": [ "componentName" ], "description": "For a single request, the response body as the http component gives it: the stream cache, or null for a response without a body. For a folder or the whole collection (no requestId), a List of PostmanRunResult, one per request, with its status and response body" } + }, "properties": { "collectionSource": { "index": 0, "kind": "path", "displayName": "Collection Source", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "postman-collection.json", "description": "The Postman Collection to use. Either a resource URI of a Collection v2.1 JSON document (classpath:, file: or http:), or the uid of a collection to fetch from the Postman cloud, which requires postmanApiKey. Default value notice: By default loads the postman-collection.json file" }, "requestId": { "index": 1, "kind": "path", "displayName": "Request Id", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The request to invoke, identified by its id in the collection or by its slugified name, for example getUserById. Use a folder id to run every request in that folder, and leave it out to run the whole collection. Append a slash to force a folder match when a request and a folder share a name." }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/servlet.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/servlet.json index 9ae3cae07472c..e3ae521f3ffd7 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/servlet.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/servlet.json @@ -38,6 +38,10 @@ "headerFilterStrategy": { "index": 10, "kind": "property", "displayName": "Header Filter Strategy", "group": "filter", "label": "filter", "required": false, "type": "object", "javaType": "org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "To use a custom org.apache.camel.spi.HeaderFilterStrategy to filter header to and from Camel message." }, "deserializationFilter": { "index": 11, "kind": "property", "displayName": "Deserialization Filter", "group": "security", "label": "advanced,security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets an ObjectInputFilter pattern (jdk.serialFilter syntax) applied when deserializing Java objects from requests or responses with Content-Type application\/x-java-serialized-object (only used when allowJavaSerializedObject or transferException is enabled). When not set, the JVM-wide jdk.serialFilter is used if present; otherwise a conservative default filter denying java.net. and otherwise allowing java., javax. and org.apache.camel. packages is applied." } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "stream", "null" ], "dependsOn": [ "transferException", "httpBinding" ], "description": "The request body as a stream cache, which can be read again (the raw stream, read once, with disableStreamCache); an empty one for a GET, null with Content-Length 0 or eagerCheckContentAvailable. The fields of a form are also headers; a multipart request is the raw multipart payload, or with attachmentMultipartBinding an empty body and its parts as attachments" }, + "consumerReply": { "carriers": [ "null", "text", "bytes", "stream", "file" ], "description": "The response body: text, bytes, a stream or a file. A Map, a List or a POJO is sent as an empty body (as its toString with chunked=false): marshal it first" } + }, "properties": { "contextPath": { "index": 0, "kind": "path", "displayName": "Context Path", "group": "consumer", "label": "consumer", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The context-path to use" }, "disableStreamCache": { "index": 1, "kind": "parameter", "displayName": "Disable Stream Cache", "group": "common", "label": "common", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Determines whether or not the raw input stream is cached or not. The Camel consumer (camel-servlet, camel-jetty etc.) will by default cache the input stream to support reading it multiple times to ensure it Camel can retrieve all data from the stream. However you can set this option to true when you for example need to access the raw stream, such as streaming it directly to a file or other persistent store. DefaultHttpBinding will copy the request input stream into a stream cache and put it into message body if this option is false to support reading the stream multiple times. If you use Servlet to bridge\/proxy an endpoint then consider enabling this option to improve performance, in case you do not need to read the message payload multiple times. The producer (camel-http) will by default cache the response body stream. If setting this option to true, then the producers will not cache the response body stream but use the response stream as-is (the stream can only be read once) as the message body." }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-ws.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-ws.json index 0e0b76f415b81..617e6cd8840f9 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-ws.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-ws.json @@ -39,6 +39,12 @@ "CamelSpringWebserviceAddressingReplyTo": { "index": 5, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "java.net.URI", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Signifies the value for the replyTo response WS-Addressing ReplyTo header that is provided by the method. See org.springframework.ws.soap.addressing.server.annotation.Action annotation for more details.", "constantName": "org.apache.camel.component.spring.ws.SpringWebserviceConstants#SPRING_WS_ADDRESSING_PRODUCER_REPLY_TO" }, "breadcrumbId": { "index": 6, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The breadcrumb id.", "constantName": "org.apache.camel.component.spring.ws.SpringWebserviceConstants#BREADCRUMB_ID" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "pojo" ], "format": "xml", "description": "The payload of the SOAP body as a javax.xml.transform.Source (a DOMSource with the default SAAJ message factory); convertBodyTo String gives the XML. The SOAP header is in the CamelSpringWebserviceSoapHeader header" }, + "consumerReply": { "carriers": [ "text", "bytes", "stream", "pojo" ], "format": "xml", "description": "The response payload as XML: a String, bytes, a stream cache, a Source or a DOM Document. A body that does not convert to a Source, such as a Map, gives an empty SOAP body without an error" }, + "producerIn": { "carriers": [ "text", "bytes", "stream", "pojo" ], "format": "xml", "description": "The request payload as XML: a String, bytes, a stream cache, a Source or a DOM Document. No body, a File, a Map or a number fails: read or marshal it to XML first" }, + "producerOut": { "carriers": [ "pojo", "null" ], "format": "xml", "description": "The payload of the SOAP response as a javax.xml.transform.Source (a DOMSource with the default SAAJ message factory), null for an empty SOAP body; also with the InOnly pattern" } + }, "properties": { "type": { "index": 0, "kind": "path", "displayName": "Type", "group": "consumer", "label": "consumer", "required": false, "type": "enum", "javaType": "org.apache.camel.component.spring.ws.type.EndpointMappingType", "enum": [ "ROOT_QNAME", "ACTION", "TO", "SOAP_ACTION", "XPATHRESULT", "URI", "URI_PATH", "BEANNAME" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.spring.ws.SpringWebserviceConfiguration", "configurationField": "configuration", "description": "Endpoint mapping type if endpoint mapping is used. rootqname - Offers the option to map web service requests based on the qualified name of the root element contained in the message. soapaction - Used to map web service requests based on the SOAP action specified in the header of the message. uri - In order to map web service requests that target a specific URI. xpathresult - Used to map web service requests based on the evaluation of an XPath expression against the incoming message. The result of the evaluation should match the XPath result specified in the endpoint URI. beanname - Allows you to reference an org.apache.camel.component.spring.ws.bean.CamelEndpointDispatcher object in order to integrate with existing (legacy) endpoint mappings like PayloadRootQNameEndpointMapping, SoapActionEndpointMapping, etc" }, "lookupKey": { "index": 1, "kind": "path", "displayName": "Lookup Key", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.spring.ws.SpringWebserviceConfiguration", "configurationField": "configuration", "description": "Endpoint mapping key if endpoint mapping is used" }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/undertow.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/undertow.json index f73e1978ba796..7117584b7be0f 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/undertow.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/undertow.json @@ -54,6 +54,12 @@ "CamelHttpMethod": { "index": 13, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The http method", "constantName": "org.apache.camel.component.undertow.UndertowConstants#HTTP_METHOD" }, "Host": { "index": 14, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The host http header", "constantName": "org.apache.camel.component.undertow.UndertowConstants#HOST_STRING" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "bytes", "null", "map", "text" ], "dependsOn": [ "undertowHttpBinding" ], "byOption": [ { "option": "useStreaming", "value": "true", "carriers": [ "stream", "null", "map" ] } ], "description": "HTTP: the request body as a byte array for POST, PUT and PATCH, null for the other methods such as GET (a body they carry is dropped); a Map of the fields of a form or a multipart request, a file as a DataHandler (also an attachment). WebSocket: a String for a text message, a byte array for a binary one, null for the events of fireWebSocketChannelEvents" }, + "consumerReply": { "carriers": [ "null", "text", "bytes", "stream", "file" ], "description": "HTTP: the response body: text, bytes, a stream or a file. A Map, a List or a POJO fails with an empty 200 response: marshal it first. A WebSocket consumer does not reply: send to the peers with a producer" }, + "producerIn": { "carriers": [ "null", "text", "bytes", "stream", "file" ], "description": "HTTP: the request body: text, bytes, a stream or a file; without the CamelHttpMethod header, a query string or no body sends a GET, and a body a POST. A Map, a List or a POJO is sent as an empty body: marshal it first. WebSocket: text and bytes or a stream to the peers connected to this endpoint, other bodies as their toString; no body sends nothing" }, + "producerOut": { "carriers": [ "bytes", "unchanged" ], "byOption": [ { "option": "useStreaming", "value": "true", "carriers": [ "stream", "unchanged" ] } ], "description": "HTTP: the response body as a byte array, an empty one (not null) for a response without a body. WebSocket: the body is kept" } + }, "properties": { "httpURI": { "index": 0, "kind": "path", "displayName": "Http URI", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.net.URI", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The url of the HTTP endpoint to use." }, "useStreaming": { "index": 1, "kind": "parameter", "displayName": "Use Streaming", "group": "common", "label": "common", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "For HTTP endpoint: if true, text and binary messages will be wrapped as java.io.InputStream before they are passed to an Exchange; otherwise they will be passed as byte. For WebSocket endpoint: if true, text and binary messages will be wrapped as java.io.Reader and java.io.InputStream respectively before they are passed to an Exchange; otherwise they will be passed as String and byte respectively." }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/vertx-websocket.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/vertx-websocket.json index ad282d35dc125..512c48a52067f 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/vertx-websocket.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/vertx-websocket.json @@ -42,6 +42,11 @@ "CamelVertxWebsocket.remoteAddress": { "index": 2, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "io.vertx.core.net.SocketAddress", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The remote address.", "constantName": "org.apache.camel.component.vertx.websocket.VertxWebsocketConstants#REMOTE_ADDRESS" }, "CamelVertxWebsocket.event": { "index": 3, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "org.apache.camel.component.vertx.websocket.VertxWebsocketEvent", "enum": [ "CLOSE", "ERROR", "MESSAGE", "OPEN" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The WebSocket event that triggered the message exchange.", "constantName": "org.apache.camel.component.vertx.websocket.VertxWebsocketConstants#EVENT" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "text", "bytes" ], "byOption": [ { "option": "fireWebSocketConnectionEvents", "value": "true", "carriers": [ "text", "bytes", "pojo", "null" ] } ], "description": "The message received: a String for a text frame, a byte array for a binary frame. With fireWebSocketConnectionEvents=true, the OPEN event has the Vert.x ServerWebSocket as body and the CLOSE event no body: the CamelVertxWebsocket.event header tells them apart" }, + "producerIn": { "carriers": [ "null", "text", "bytes", "stream", "file" ], "description": "A String is sent as a text frame and a byte array as a binary frame; any other body is converted to a String and sent as a text frame, so a stream with binary content must be converted to bytes first, and a Map or a POJO is sent as its toString: marshal it first. No body sends nothing" }, + "producerOut": { "carriers": [ "unchanged" ] } + }, "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.vertx.websocket.VertxWebsocketConfiguration", "configurationField": "configuration", "description": "WebSocket hostname, such as localhost or a remote host when in client mode." }, "port": { "index": 1, "kind": "path", "displayName": "Port", "group": "common", "label": "", "required": true, "type": "integer", "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.websocket.VertxWebsocketConfiguration", "configurationField": "configuration", "description": "WebSocket port number to use." }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/webhook.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/webhook.json index 8aca390e6cabe..ae8bcf2dd4347 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/webhook.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/webhook.json @@ -34,6 +34,10 @@ "autowiredEnabled": { "index": 6, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." }, "configuration": { "index": 7, "kind": "property", "displayName": "Configuration", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.webhook.WebhookConfiguration", "deprecated": false, "autowired": false, "secret": false, "description": "Set the default configuration for the webhook meta-component." } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "unknown" ], "description": "The body the webhook handler of the delegate component (endpointUri) makes of the HTTP request: the same body as its polling consumer, such as an IncomingMessage (or another update) for Telegram, an Event for ClickUp, or the JSON as a String for WhatsApp" }, + "consumerReply": { "carriers": [ "any" ], "description": "The delegate component sets the HTTP response body itself after the route: Telegram and ClickUp reply with an empty body, WhatsApp with the request content, whatever body the route ends with" } + }, "properties": { "endpointUri": { "index": 0, "kind": "path", "displayName": "Endpoint Uri", "group": "consumer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.webhook.WebhookConfiguration", "configurationField": "configuration", "description": "The delegate uri. Must belong to a component that supports webhooks." }, "webhookAutoRegister": { "index": 1, "kind": "parameter", "displayName": "Webhook Auto Register", "group": "consumer", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.webhook.WebhookConfiguration", "configurationField": "configuration", "description": "Automatically register the webhook at startup and unregister it on shutdown." }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/cxf-component.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/cxf-component.adoc index b2c500584df6a..747329da3c220 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/cxf-component.adoc +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/cxf-component.adoc @@ -688,7 +688,7 @@ assertEquals("echo " + TEST_MESSAGE, result.get(0), "Reply body on Camel is wron `PAYLOAD` means that you process the payload from the SOAP envelope as a native CxfPayload. `Message.getBody()` will return a -`org.apache.camel.component.cxf.CxfPayload` object, with getters +`org.apache.camel.component.cxf.common.CxfPayload` object, with getters for SOAP message headers and the SOAP body. See https://github.com/apache/camel/blob/main/components/camel-cxf/camel-cxf-soap/src/test/java/org/apache/camel/component/cxf/jaxws/CxfConsumerPayloadTest.java#L68[CxfConsumerPayloadTest]: diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/cxfrs-component.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/cxfrs-component.adoc index a68a5a2e38675..94a2892c2e334 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/cxfrs-component.adoc +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/cxfrs-component.adoc @@ -120,12 +120,12 @@ The header name matches the Body Part name. Additionally, the following rules apply to the *Response mapping*: -* If the message body type is different to `javax.ws.rs.core.Response` +* If the message body type is different to `jakarta.ws.rs.core.Response` (user-built response), a new `Response` is created and the message body is set as the entity (so long it's not null). The response status code is taken from the `Exchange.HTTP_RESPONSE_CODE` header, or defaults to 200 OK if not present. -* If the message body type is equal to `javax.ws.rs.core.Response`, it +* If the message body type is equal to `jakarta.ws.rs.core.Response`, it means that the user has built a custom response, and therefore it is respected, and it becomes the final response. * In all cases, Camel headers permitted by custom or default diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/jetty-component.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/jetty-component.adoc index 5ea825fcf50f5..84d5c296a7bb1 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/jetty-component.adoc +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/jetty-component.adoc @@ -19,10 +19,12 @@ behaves as a simple Web server. *Stream* Jetty is stream-based, which means the input it receives is -submitted to Camel as a stream. That means you will only be able to read -the content of the stream *once*. +submitted to Camel as a stream. By default the consumer copies the request +body into a stream cache, which can be read more than once. With +`disableStreamCache=true` the body is the raw request stream, and you will +only be able to read the content of the stream *once*. If you find a situation where the message body appears to be empty, or -you need to access the Exchange.HTTP_RESPONSE_CODE data multiple times +you need to access the body multiple times (e.g.: doing multicasting, or redelivery error handling), you should use Stream caching or convert the message body to a `String` which is safe to be re-read multiple times. diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/netty-http-component.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/netty-http-component.adoc index 4a8023084c2ae..2373c69dce3a2 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/netty-http-component.adoc +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/netty-http-component.adoc @@ -20,17 +20,16 @@ component to simplify HTTP transport with xref:netty-component.adoc[Netty]. ==== *Stream* -Netty is stream-based, which means the input it receives is submitted to -Camel as a stream. That means you will only be able to read the content -of the stream *once*. If you find a situation where the message body appears to be empty, or -you need to access the data multiple times (eg: doing multicasting, or -redelivery error handling), you should use Stream caching or convert the -message body to a `String` which is safe to be re-read multiple times. - -Note also that Netty HTTP reads the entire stream into memory using +Netty HTTP reads the entire request into memory using `io.netty.handler.codec.http.HttpObjectAggregator` to build the entire -full http message. But the resulting message is still a stream-based -message that is readable once. +full http message. The consumer gives the request body as a Camel stream cache, +which can be read multiple times, and the producer gives the response body as a byte array. + +With `disableStreamCache=true` the body is the raw Netty `ByteBuf` instead (or an `InputStream` +for a chunked message), which you can only read *once*. If you find a situation where the +message body then appears to be empty, or you need to access the data multiple times (eg: doing +multicasting, or redelivery error handling), convert the message body to a `String` or a `byte[]` +which is safe to be re-read multiple times. ==== Maven users will need to add the following dependency to their `pom.xml` diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/servlet-component.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/servlet-component.adoc index 34940add1aabe..96ca7980cb456 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/servlet-component.adoc +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/servlet-component.adoc @@ -35,8 +35,10 @@ for this component: *Stream* Servlet is stream-based, which means the input it receives is submitted -to Camel as a stream. That means you will only be able to read the -content of the stream *once*. If you find a situation where the message +to Camel as a stream. By default the consumer copies the request body into +a stream cache, which can be read more than once. With +`disableStreamCache=true` the body is the raw request stream, and you will +only be able to read the content of the stream *once*. If you find a situation where the message body appears to be empty, or you need to access the data multiple times (eg: doing multicasting, or redelivery error handling), you should use Stream caching or convert the message body to diff --git a/components/camel-atmosphere-websocket/src/generated/resources/META-INF/org/apache/camel/component/atmosphere/websocket/atmosphere-websocket.json b/components/camel-atmosphere-websocket/src/generated/resources/META-INF/org/apache/camel/component/atmosphere/websocket/atmosphere-websocket.json index 4bf301ec752a2..c5200281fada9 100644 --- a/components/camel-atmosphere-websocket/src/generated/resources/META-INF/org/apache/camel/component/atmosphere/websocket/atmosphere-websocket.json +++ b/components/camel-atmosphere-websocket/src/generated/resources/META-INF/org/apache/camel/component/atmosphere/websocket/atmosphere-websocket.json @@ -45,6 +45,11 @@ "CamelAtmosphereWebsocketEventType": { "index": 2, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "important": true, "description": "The type of event received. It can be ONOPEN_EVENT_TYPE, ONERROR_EVENT_TYPE or ONCLOSE_EVENT_TYPE.", "constantName": "org.apache.camel.component.atmosphere.websocket.WebsocketConstants#EVENT_TYPE" }, "CamelAtmosphereWebsocketErrorType": { "index": 3, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The type of error that occurred. It can be MESSAGE_NOT_SENT_ERROR_TYPE.", "constantName": "org.apache.camel.component.atmosphere.websocket.WebsocketConstants#ERROR_TYPE" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "text", "bytes", "null" ], "byOption": [ { "option": "useStreaming", "value": "true", "carriers": [ "stream", "null" ] } ], "description": "A String for a text message, a byte array for a binary one; null for the open, close and error events (the servlet init parameter events=true). A message the producer could not deliver comes back with the CamelAtmosphereWebsocketErrorType header. The consumer does not reply" }, + "producerIn": { "carriers": [ "null", "text", "bytes", "stream" ], "description": "Text or a Reader as a text message, bytes or an InputStream as a binary one; other bodies as their toString. No body sends nothing. Sent to all peers with sendToAll, otherwise to the connection key headers" }, + "producerOut": { "carriers": [ "unchanged" ], "description": "The body is kept" } + }, "properties": { "servicePath": { "index": 0, "kind": "path", "displayName": "Service Path", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Name of websocket endpoint" }, "chunked": { "index": 1, "kind": "parameter", "displayName": "Chunked", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "If this option is false the Servlet will disable the HTTP streaming and set the content-length header on the response" }, diff --git a/components/camel-atmosphere-websocket/src/main/java/org/apache/camel/component/atmosphere/websocket/WebsocketEndpoint.java b/components/camel-atmosphere-websocket/src/main/java/org/apache/camel/component/atmosphere/websocket/WebsocketEndpoint.java index 8885836687ffd..0d68cdb777e59 100644 --- a/components/camel-atmosphere-websocket/src/main/java/org/apache/camel/component/atmosphere/websocket/WebsocketEndpoint.java +++ b/components/camel-atmosphere-websocket/src/main/java/org/apache/camel/component/atmosphere/websocket/WebsocketEndpoint.java @@ -24,6 +24,9 @@ import org.apache.camel.Processor; import org.apache.camel.Producer; import org.apache.camel.component.servlet.ServletEndpoint; +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; @@ -47,6 +50,18 @@ annotations = { "protocol=http", }) +@BodyTypes(consumerOut = @BodyType(value = { Carrier.TEXT, Carrier.BYTES, Carrier.NULL }, + byOption = @BodyType.When(option = "useStreaming", value = "true", + carriers = { Carrier.STREAM, Carrier.NULL }), + description = "A String for a text message, a byte array for a binary one; null for the" + + " open, close and error events (the servlet init parameter events=true)." + + " A message the producer could not deliver comes back with the" + + " CamelAtmosphereWebsocketErrorType header. The consumer does not reply"), + producerIn = @BodyType(value = { Carrier.NULL, Carrier.TEXT, Carrier.BYTES, Carrier.STREAM }, + description = "Text or a Reader as a text message, bytes or an InputStream as a binary" + + " one; other bodies as their toString. No body sends nothing. Sent to all" + + " peers with sendToAll, otherwise to the connection key headers"), + producerOut = @BodyType(value = Carrier.UNCHANGED, description = "The body is kept")) public class WebsocketEndpoint extends ServletEndpoint { private WebSocketStore store; diff --git a/components/camel-cxf/camel-cxf-rest/src/generated/resources/META-INF/org/apache/camel/component/cxf/jaxrs/cxfrs.json b/components/camel-cxf/camel-cxf-rest/src/generated/resources/META-INF/org/apache/camel/component/cxf/jaxrs/cxfrs.json index d075d9619913b..abaef59b426f8 100644 --- a/components/camel-cxf/camel-cxf-rest/src/generated/resources/META-INF/org/apache/camel/component/cxf/jaxrs/cxfrs.json +++ b/components/camel-cxf/camel-cxf-rest/src/generated/resources/META-INF/org/apache/camel/component/cxf/jaxrs/cxfrs.json @@ -50,6 +50,12 @@ "CamelCxfRsQueryMap": { "index": 14, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Map", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The query map", "constantName": "org.apache.camel.component.cxf.common.message.CxfConstants#CAMEL_CXF_RS_QUERY_MAP" }, "CamelCxfRsOperationResourceInfoStack": { "index": 15, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "org.apache.cxf.jaxrs.model.OperationResourceInfoStack", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The stack of MethodInvocationInfo representing resources path when JAX-RS invocation looks for target.", "constantName": "org.apache.camel.component.cxf.common.message.CxfConstants#CAMEL_CXF_RS_OPERATION_RESOURCE_INFO_STACK" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "list" ], "javaType": "org.apache.cxf.message.MessageContentsList", "dependsOn": [ "performInvocation" ], "byOption": [ { "option": "bindingStyle", "value": "SimpleConsumer", "carriers": [ "unknown" ] }, { "option": "bindingStyle", "value": "Custom", "carriers": [ "unknown" ] } ], "description": "Default: a MessageContentsList of the parameters of the resource method, with its name in the CamelCxfOperationName header. SimpleConsumer: the request entity as the method declares it (a String, an InputStream, a JAXB bean), with the path, query and header parameters in headers; the MessageContentsList when the method has no entity, such as a GET" }, + "consumerReply": { "carriers": [ "null", "text", "bytes", "stream", "file", "pojo" ], "byOption": [ { "option": "bindingStyle", "value": "Custom", "carriers": [ "any" ] } ], "description": "The response entity: a jakarta.ws.rs.core.Response, or text, bytes, a stream, a file, or an object a JAX-RS provider writes for the Content-Type (a JAXB bean as XML); a Map or a List fails without a provider for it. With the Default binding the request MessageContentsList fails: set the reply body" }, + "producerIn": { "carriers": [ "null", "text", "bytes", "stream", "file", "pojo" ], "byOption": [ { "option": "httpClientAPI", "value": "false", "carriers": [ "list", "text", "value", "pojo", "null" ] } ], "description": "The request entity, written for the Content-Type header: text, bytes, a stream, a file or an object a JAX-RS provider writes; of a List only the first element is sent, and a Map fails. A GET sends no body. With httpClientAPI=false: the parameters of the resource method named by the CamelCxfOperationName header, as a List or the one parameter" }, + "producerOut": { "carriers": [ "pojo" ], "byOption": [ { "option": "httpClientAPI", "value": "false", "carriers": [ "unknown" ] } ], "description": "A jakarta.ws.rs.core.Response whose entity is the response stream, read once (it converts to a String or an InputStream); the entity read as the class in the CamelCxfRsResponseClass header when that is set. With httpClientAPI=false: the return value of the resource method, null for a void one" } + }, "properties": { "beanId": { "index": 0, "kind": "path", "displayName": "Bean Id", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "To lookup an existing configured CxfRsEndpoint. Must used bean: as prefix." }, "address": { "index": 1, "kind": "path", "displayName": "Address", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The service publish address." }, diff --git a/components/camel-cxf/camel-cxf-rest/src/main/docs/cxfrs-component.adoc b/components/camel-cxf/camel-cxf-rest/src/main/docs/cxfrs-component.adoc index a68a5a2e38675..94a2892c2e334 100644 --- a/components/camel-cxf/camel-cxf-rest/src/main/docs/cxfrs-component.adoc +++ b/components/camel-cxf/camel-cxf-rest/src/main/docs/cxfrs-component.adoc @@ -120,12 +120,12 @@ The header name matches the Body Part name. Additionally, the following rules apply to the *Response mapping*: -* If the message body type is different to `javax.ws.rs.core.Response` +* If the message body type is different to `jakarta.ws.rs.core.Response` (user-built response), a new `Response` is created and the message body is set as the entity (so long it's not null). The response status code is taken from the `Exchange.HTTP_RESPONSE_CODE` header, or defaults to 200 OK if not present. -* If the message body type is equal to `javax.ws.rs.core.Response`, it +* If the message body type is equal to `jakarta.ws.rs.core.Response`, it means that the user has built a custom response, and therefore it is respected, and it becomes the final response. * In all cases, Camel headers permitted by custom or default diff --git a/components/camel-cxf/camel-cxf-rest/src/main/java/org/apache/camel/component/cxf/jaxrs/CxfRsEndpoint.java b/components/camel-cxf/camel-cxf-rest/src/main/java/org/apache/camel/component/cxf/jaxrs/CxfRsEndpoint.java index 297bffe12ba7e..aede2015b59e4 100644 --- a/components/camel-cxf/camel-cxf-rest/src/main/java/org/apache/camel/component/cxf/jaxrs/CxfRsEndpoint.java +++ b/components/camel-cxf/camel-cxf-rest/src/main/java/org/apache/camel/component/cxf/jaxrs/CxfRsEndpoint.java @@ -35,6 +35,9 @@ import org.apache.camel.component.cxf.common.NullFaultListener; import org.apache.camel.component.cxf.common.message.CxfConstants; import org.apache.camel.http.base.cookie.CookieHandler; +import org.apache.camel.spi.BodyType; +import org.apache.camel.spi.BodyType.Carrier; +import org.apache.camel.spi.BodyTypes; import org.apache.camel.spi.HeaderFilterStrategy; import org.apache.camel.spi.HeaderFilterStrategyAware; import org.apache.camel.spi.Metadata; @@ -75,6 +78,48 @@ @Metadata(annotations = { "protocol=http", }) +@BodyTypes(consumerOut = @BodyType(value = Carrier.LIST, javaType = "org.apache.cxf.message.MessageContentsList", + dependsOn = "performInvocation", + byOption = { + @BodyType.When(option = "bindingStyle", value = "SimpleConsumer", + carriers = Carrier.UNKNOWN), + @BodyType.When(option = "bindingStyle", value = "Custom", + carriers = Carrier.UNKNOWN) }, + description = "Default: a MessageContentsList of the parameters of the resource method," + + " with its name in the CamelCxfOperationName header. SimpleConsumer: the" + + " request entity as the method declares it (a String, an InputStream, a" + + " JAXB bean), with the path, query and header parameters in headers; the" + + " MessageContentsList when the method has no entity, such as a GET"), + consumerReply = @BodyType(value = { + Carrier.NULL, Carrier.TEXT, Carrier.BYTES, Carrier.STREAM, Carrier.FILE, + Carrier.POJO }, + byOption = @BodyType.When(option = "bindingStyle", value = "Custom", + carriers = Carrier.ANY), + description = "The response entity: a jakarta.ws.rs.core.Response, or text, bytes, a" + + " stream, a file, or an object a JAX-RS provider writes for the" + + " Content-Type (a JAXB bean as XML); a Map or a List fails without a" + + " provider for it. With the Default binding the request" + + " MessageContentsList fails: set the reply body"), + producerIn = @BodyType(value = { + Carrier.NULL, Carrier.TEXT, Carrier.BYTES, Carrier.STREAM, Carrier.FILE, + Carrier.POJO }, + byOption = @BodyType.When(option = "httpClientAPI", value = "false", + carriers = { + Carrier.LIST, Carrier.TEXT, Carrier.VALUE, + Carrier.POJO, Carrier.NULL }), + description = "The request entity, written for the Content-Type header: text, bytes, a" + + " stream, a file or an object a JAX-RS provider writes; of a List only" + + " the first element is sent, and a Map fails. A GET sends no body. With" + + " httpClientAPI=false: the parameters of the resource method named by the" + + " CamelCxfOperationName header, as a List or the one parameter"), + producerOut = @BodyType(value = Carrier.POJO, + byOption = @BodyType.When(option = "httpClientAPI", value = "false", + carriers = Carrier.UNKNOWN), + description = "A jakarta.ws.rs.core.Response whose entity is the response stream, read" + + " once (it converts to a String or an InputStream); the entity read as the" + + " class in the CamelCxfRsResponseClass header when that is set. With" + + " httpClientAPI=false: the return value of the resource method, null for" + + " a void one")) public class CxfRsEndpoint extends DefaultEndpoint implements HeaderFilterStrategyAware { private static final Logger LOG = LoggerFactory.getLogger(CxfRsEndpoint.class); diff --git a/components/camel-cxf/camel-cxf-soap/src/generated/resources/META-INF/org/apache/camel/component/cxf/jaxws/cxf.json b/components/camel-cxf/camel-cxf-soap/src/generated/resources/META-INF/org/apache/camel/component/cxf/jaxws/cxf.json index 578d46bed3144..d757fadf9c2a9 100644 --- a/components/camel-cxf/camel-cxf-soap/src/generated/resources/META-INF/org/apache/camel/component/cxf/jaxws/cxf.json +++ b/components/camel-cxf/camel-cxf-soap/src/generated/resources/META-INF/org/apache/camel/component/cxf/jaxws/cxf.json @@ -41,6 +41,12 @@ "CamelAuthentication": { "index": 4, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "javax.security.auth.Subject", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The authentication", "constantName": "org.apache.camel.component.cxf.common.message.CxfConstants#AUTHENTICATION" }, "RequestContext": { "index": 5, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Object", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The request context", "constantName": "org.apache.camel.component.cxf.common.message.CxfConstants#REQUEST_CONTEXT" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "list", "null" ], "byOption": [ { "option": "dataFormat", "value": "PAYLOAD", "carriers": [ "pojo" ], "javaType": "org.apache.camel.component.cxf.common.CxfPayload" }, { "option": "dataFormat", "value": "RAW", "carriers": [ "stream" ] }, { "option": "dataFormat", "value": "MESSAGE", "carriers": [ "stream" ] }, { "option": "dataFormat", "value": "CXF_MESSAGE", "carriers": [ "pojo" ], "javaType": "jakarta.xml.soap.SOAPMessage" } ], "description": "POJO: a MessageContentsList of the parameters of the operation, typed as the service class declares them, with its name in the CamelCxfOperationName header; null for an operation without parameters. PAYLOAD: a CxfPayload of the elements of the soap:Body and the SOAP headers. RAW: the stream of the whole SOAP envelope, without the operation name. CXF_MESSAGE: the SAAJ SOAPMessage" }, + "consumerReply": { "carriers": [ "text", "value", "pojo", "list", "null" ], "byOption": [ { "option": "dataFormat", "value": "PAYLOAD", "carriers": [ "pojo", "text", "bytes", "stream", "null" ] }, { "option": "dataFormat", "value": "RAW", "carriers": [ "text", "bytes", "stream", "file", "null" ] }, { "option": "dataFormat", "value": "MESSAGE", "carriers": [ "text", "bytes", "stream", "file", "null" ] }, { "option": "dataFormat", "value": "CXF_MESSAGE", "carriers": [ "pojo" ] } ], "description": "POJO: the return value of the operation, of the type the service class declares, or a List or array of it and the out and holder parameters; another type is a SOAP fault, so the request MessageContentsList only fits an echo. PAYLOAD: a CxfPayload, or the XML of the soap:Body contents as text, bytes, a stream or a DOM; a body that does not convert sends an empty soap:Body. RAW: the whole SOAP envelope as text, bytes, a stream or a file. CXF_MESSAGE: a SOAPMessage or a javax.xml.transform Source; text or a stream sends an empty envelope" }, + "producerIn": { "carriers": [ "list", "text", "value", "pojo", "null" ], "byOption": [ { "option": "dataFormat", "value": "PAYLOAD", "carriers": [ "pojo", "text", "bytes", "stream", "file" ] }, { "option": "dataFormat", "value": "RAW", "carriers": [ "text", "bytes", "stream", "file" ] }, { "option": "dataFormat", "value": "MESSAGE", "carriers": [ "text", "bytes", "stream", "file" ] }, { "option": "dataFormat", "value": "CXF_MESSAGE", "carriers": [ "pojo" ] } ], "description": "POJO: the parameters of the operation (the CamelCxfOperationName header or defaultOperationName) as a List or an array, or the one parameter as the body; each of the type the service class declares. A body that is not a List is split like the split EIP does, so text with a comma or a byte array is several parameters: wrap it in a List. PAYLOAD: a CxfPayload, or the XML of the soap:Body contents as text, bytes, a stream, a file or a DOM. RAW: the whole SOAP envelope. CXF_MESSAGE: a SOAPMessage or a javax.xml.transform Source" }, + "producerOut": { "carriers": [ "list", "null", "unchanged" ], "byOption": [ { "option": "dataFormat", "value": "PAYLOAD", "carriers": [ "pojo" ], "javaType": "org.apache.camel.component.cxf.common.CxfPayload" }, { "option": "dataFormat", "value": "RAW", "carriers": [ "stream" ] }, { "option": "dataFormat", "value": "MESSAGE", "carriers": [ "stream" ] }, { "option": "dataFormat", "value": "CXF_MESSAGE", "carriers": [ "pojo" ], "javaType": "jakarta.xml.soap.SOAPMessage" } ], "description": "POJO: a MessageContentsList with the return value of the operation first, then the out and holder parameters; null for a void operation, and the body unchanged for a one-way one. PAYLOAD: a CxfPayload of the soap:Body contents. RAW: the stream of the SOAP envelope of the response, read once. CXF_MESSAGE: the SAAJ SOAPMessage" } + }, "properties": { "beanId": { "index": 0, "kind": "path", "displayName": "Bean Id", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "To lookup an existing configured CxfEndpoint. Must used bean: as prefix." }, "address": { "index": 1, "kind": "path", "displayName": "Address", "group": "service", "label": "service", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The service publish address." }, diff --git a/components/camel-cxf/camel-cxf-soap/src/main/docs/cxf-component.adoc b/components/camel-cxf/camel-cxf-soap/src/main/docs/cxf-component.adoc index b2c500584df6a..747329da3c220 100644 --- a/components/camel-cxf/camel-cxf-soap/src/main/docs/cxf-component.adoc +++ b/components/camel-cxf/camel-cxf-soap/src/main/docs/cxf-component.adoc @@ -688,7 +688,7 @@ assertEquals("echo " + TEST_MESSAGE, result.get(0), "Reply body on Camel is wron `PAYLOAD` means that you process the payload from the SOAP envelope as a native CxfPayload. `Message.getBody()` will return a -`org.apache.camel.component.cxf.CxfPayload` object, with getters +`org.apache.camel.component.cxf.common.CxfPayload` object, with getters for SOAP message headers and the SOAP body. See https://github.com/apache/camel/blob/main/components/camel-cxf/camel-cxf-soap/src/test/java/org/apache/camel/component/cxf/jaxws/CxfConsumerPayloadTest.java#L68[CxfConsumerPayloadTest]: diff --git a/components/camel-cxf/camel-cxf-soap/src/main/java/org/apache/camel/component/cxf/jaxws/CxfEndpoint.java b/components/camel-cxf/camel-cxf-soap/src/main/java/org/apache/camel/component/cxf/jaxws/CxfEndpoint.java index 3deb088a40d41..1849311197058 100644 --- a/components/camel-cxf/camel-cxf-soap/src/main/java/org/apache/camel/component/cxf/jaxws/CxfEndpoint.java +++ b/components/camel-cxf/camel-cxf-soap/src/main/java/org/apache/camel/component/cxf/jaxws/CxfEndpoint.java @@ -66,6 +66,9 @@ import org.apache.camel.component.cxf.feature.RAWDataFormatFeature; import org.apache.camel.component.cxf.transport.header.CxfHeaderFilterStrategy; import org.apache.camel.http.base.cookie.CookieHandler; +import org.apache.camel.spi.BodyType; +import org.apache.camel.spi.BodyType.Carrier; +import org.apache.camel.spi.BodyTypes; import org.apache.camel.spi.HeaderFilterStrategy; import org.apache.camel.spi.HeaderFilterStrategyAware; import org.apache.camel.spi.Metadata; @@ -132,6 +135,81 @@ @Metadata(annotations = { "protocol=http", }) +@BodyTypes(consumerOut = @BodyType(value = { Carrier.LIST, Carrier.NULL }, + byOption = { + @BodyType.When(option = "dataFormat", value = "PAYLOAD", carriers = Carrier.POJO, + javaType = "org.apache.camel.component.cxf.common.CxfPayload"), + @BodyType.When(option = "dataFormat", value = "RAW", carriers = Carrier.STREAM), + @BodyType.When(option = "dataFormat", value = "MESSAGE", carriers = Carrier.STREAM), + @BodyType.When(option = "dataFormat", value = "CXF_MESSAGE", carriers = Carrier.POJO, + javaType = "jakarta.xml.soap.SOAPMessage") }, + description = "POJO: a MessageContentsList of the parameters of the operation, typed as the" + + " service class declares them, with its name in the CamelCxfOperationName" + + " header; null for an operation without parameters. PAYLOAD: a CxfPayload" + + " of the elements of the soap:Body and the SOAP headers. RAW: the stream of" + + " the whole SOAP envelope, without the operation name. CXF_MESSAGE: the SAAJ" + + " SOAPMessage"), + consumerReply = @BodyType(value = { Carrier.TEXT, Carrier.VALUE, Carrier.POJO, Carrier.LIST, Carrier.NULL }, + byOption = { + @BodyType.When(option = "dataFormat", value = "PAYLOAD", + carriers = { + Carrier.POJO, Carrier.TEXT, Carrier.BYTES, + Carrier.STREAM, Carrier.NULL }), + @BodyType.When(option = "dataFormat", value = "RAW", + carriers = { + Carrier.TEXT, Carrier.BYTES, Carrier.STREAM, + Carrier.FILE, Carrier.NULL }), + @BodyType.When(option = "dataFormat", value = "MESSAGE", + carriers = { + Carrier.TEXT, Carrier.BYTES, Carrier.STREAM, + Carrier.FILE, Carrier.NULL }), + @BodyType.When(option = "dataFormat", value = "CXF_MESSAGE", + carriers = Carrier.POJO) }, + description = "POJO: the return value of the operation, of the type the service class" + + " declares, or a List or array of it and the out and holder parameters;" + + " another type is a SOAP fault, so the request MessageContentsList only" + + " fits an echo. PAYLOAD: a CxfPayload, or the XML of the soap:Body" + + " contents as text, bytes, a stream or a DOM; a body that does not convert" + + " sends an empty soap:Body. RAW: the whole SOAP envelope as text, bytes, a" + + " stream or a file. CXF_MESSAGE: a SOAPMessage or a javax.xml.transform" + + " Source; text or a stream sends an empty envelope"), + producerIn = @BodyType(value = { Carrier.LIST, Carrier.TEXT, Carrier.VALUE, Carrier.POJO, Carrier.NULL }, + byOption = { + @BodyType.When(option = "dataFormat", value = "PAYLOAD", + carriers = { + Carrier.POJO, Carrier.TEXT, Carrier.BYTES, + Carrier.STREAM, Carrier.FILE }), + @BodyType.When(option = "dataFormat", value = "RAW", + carriers = { + Carrier.TEXT, Carrier.BYTES, Carrier.STREAM, + Carrier.FILE }), + @BodyType.When(option = "dataFormat", value = "MESSAGE", + carriers = { + Carrier.TEXT, Carrier.BYTES, Carrier.STREAM, + Carrier.FILE }), + @BodyType.When(option = "dataFormat", value = "CXF_MESSAGE", + carriers = Carrier.POJO) }, + description = "POJO: the parameters of the operation (the CamelCxfOperationName header or" + + " defaultOperationName) as a List or an array, or the one parameter as" + + " the body; each of the type the service class declares. A body that is" + + " not a List is split like the split EIP does, so text with a comma or a" + + " byte array is several parameters: wrap it in a List. PAYLOAD: a" + + " CxfPayload, or the XML of the soap:Body contents as text, bytes, a stream," + + " a file or a DOM. RAW: the whole SOAP envelope. CXF_MESSAGE: a SOAPMessage" + + " or a javax.xml.transform Source"), + producerOut = @BodyType(value = { Carrier.LIST, Carrier.NULL, Carrier.UNCHANGED }, + byOption = { + @BodyType.When(option = "dataFormat", value = "PAYLOAD", carriers = Carrier.POJO, + javaType = "org.apache.camel.component.cxf.common.CxfPayload"), + @BodyType.When(option = "dataFormat", value = "RAW", carriers = Carrier.STREAM), + @BodyType.When(option = "dataFormat", value = "MESSAGE", carriers = Carrier.STREAM), + @BodyType.When(option = "dataFormat", value = "CXF_MESSAGE", carriers = Carrier.POJO, + javaType = "jakarta.xml.soap.SOAPMessage") }, + description = "POJO: a MessageContentsList with the return value of the operation first," + + " then the out and holder parameters; null for a void operation, and the" + + " body unchanged for a one-way one. PAYLOAD: a CxfPayload of the" + + " soap:Body contents. RAW: the stream of the SOAP envelope of the" + + " response, read once. CXF_MESSAGE: the SAAJ SOAPMessage")) public class CxfEndpoint extends DefaultEndpoint implements AsyncEndpoint, HeaderFilterStrategyAware, Cloneable { private static final Logger LOG = LoggerFactory.getLogger(CxfEndpoint.class); diff --git a/components/camel-jetty/src/generated/resources/META-INF/org/apache/camel/component/jetty12/jetty.json b/components/camel-jetty/src/generated/resources/META-INF/org/apache/camel/component/jetty12/jetty.json index ea731d7618ccf..5e71ffa203626 100644 --- a/components/camel-jetty/src/generated/resources/META-INF/org/apache/camel/component/jetty12/jetty.json +++ b/components/camel-jetty/src/generated/resources/META-INF/org/apache/camel/component/jetty12/jetty.json @@ -69,6 +69,10 @@ "CamelServletContextPath": { "index": 0, "kind": "header", "displayName": "", "group": "consumer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The servlet context path used", "constantName": "org.apache.camel.component.jetty.JettyHttpConstants#SERVLET_CONTEXT_PATH" }, "CamelHttpPath": { "index": 1, "kind": "header", "displayName": "", "group": "consumer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Request URI's path, the header will be used to build the request URI with the HTTP_URI.", "constantName": "org.apache.camel.component.jetty.JettyHttpConstants#HTTP_PATH" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "stream", "null" ], "dependsOn": [ "transferException", "httpBinding" ], "description": "The request body as a stream cache, which can be read again (the raw stream, read once, with disableStreamCache); an empty one for a GET, null with Content-Length 0 or eagerCheckContentAvailable. The fields of a form are also headers; a multipart upload leaves the body empty and gives its files as attachments and DataHandler headers" }, + "consumerReply": { "carriers": [ "null", "text", "bytes", "stream", "file" ], "description": "The response body: text, bytes, a stream or a file. A Map, a List or a POJO is sent as an empty body (as its toString with chunked=false): marshal it first" } + }, "properties": { "httpUri": { "index": 0, "kind": "path", "displayName": "Http Uri", "group": "common", "label": "common", "required": true, "type": "string", "javaType": "java.net.URI", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The url of the HTTP endpoint to call." }, "headerFilterStrategy": { "index": 1, "kind": "parameter", "displayName": "Header Filter Strategy", "group": "common (advanced)", "label": "common,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "To use a custom HeaderFilterStrategy to filter header to and from Camel message." }, diff --git a/components/camel-jetty/src/main/docs/jetty-component.adoc b/components/camel-jetty/src/main/docs/jetty-component.adoc index 5ea825fcf50f5..84d5c296a7bb1 100644 --- a/components/camel-jetty/src/main/docs/jetty-component.adoc +++ b/components/camel-jetty/src/main/docs/jetty-component.adoc @@ -19,10 +19,12 @@ behaves as a simple Web server. *Stream* Jetty is stream-based, which means the input it receives is -submitted to Camel as a stream. That means you will only be able to read -the content of the stream *once*. +submitted to Camel as a stream. By default the consumer copies the request +body into a stream cache, which can be read more than once. With +`disableStreamCache=true` the body is the raw request stream, and you will +only be able to read the content of the stream *once*. If you find a situation where the message body appears to be empty, or -you need to access the Exchange.HTTP_RESPONSE_CODE data multiple times +you need to access the body multiple times (e.g.: doing multicasting, or redelivery error handling), you should use Stream caching or convert the message body to a `String` which is safe to be re-read multiple times. diff --git a/components/camel-jetty/src/main/java/org/apache/camel/component/jetty12/JettyHttpEndpoint12.java b/components/camel-jetty/src/main/java/org/apache/camel/component/jetty12/JettyHttpEndpoint12.java index d33c25fd60e58..7d632ced07848 100644 --- a/components/camel-jetty/src/main/java/org/apache/camel/component/jetty12/JettyHttpEndpoint12.java +++ b/components/camel-jetty/src/main/java/org/apache/camel/component/jetty12/JettyHttpEndpoint12.java @@ -25,6 +25,9 @@ import org.apache.camel.component.jetty.JettyHttpConstants; import org.apache.camel.component.jetty.JettyHttpEndpoint; import org.apache.camel.http.common.HttpBinding; +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; @@ -39,6 +42,16 @@ annotations = { "protocol=http" }) +@BodyTypes(consumerOut = @BodyType(value = { Carrier.STREAM, Carrier.NULL }, dependsOn = { "transferException", "httpBinding" }, + description = "The request body as a stream cache, which can be read again (the raw stream," + + " read once, with disableStreamCache); an empty one for a GET, null with" + + " Content-Length 0 or eagerCheckContentAvailable. The fields of a form are" + + " also headers; a multipart upload leaves the body empty and gives its files" + + " as attachments and DataHandler headers"), + consumerReply = @BodyType(value = { Carrier.NULL, Carrier.TEXT, Carrier.BYTES, Carrier.STREAM, Carrier.FILE }, + description = "The response body: text, bytes, a stream or a file. A Map, a List or a POJO" + + " is sent as an empty body (as its toString with chunked=false): marshal" + + " it first")) public class JettyHttpEndpoint12 extends JettyHttpEndpoint implements AsyncEndpoint { private HttpBinding binding; diff --git a/components/camel-netty-http/src/generated/resources/META-INF/org/apache/camel/component/netty/http/netty-http.json b/components/camel-netty-http/src/generated/resources/META-INF/org/apache/camel/component/netty/http/netty-http.json index fced770f492c3..226aa49cc714b 100644 --- a/components/camel-netty-http/src/generated/resources/META-INF/org/apache/camel/component/netty/http/netty-http.json +++ b/components/camel-netty-http/src/generated/resources/META-INF/org/apache/camel/component/netty/http/netty-http.json @@ -131,6 +131,12 @@ "CamelNettyRequestTimeout": { "index": 22, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The read timeout.", "constantName": "org.apache.camel.component.netty.NettyConstants#NETTY_REQUEST_TIMEOUT" }, "CamelNettyChannel": { "index": 23, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "io.netty.channel.Channel", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The Netty Channel object.", "constantName": "org.apache.camel.component.netty.NettyConstants#NETTY_CHANNEL" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "stream" ], "javaType": "org.apache.camel.component.netty.http.NettyChannelBufferStreamCache", "dependsOn": [ "nettyHttpBinding" ], "byOption": [ { "option": "disableStreamCache", "value": "true", "carriers": [ "pojo", "stream" ] }, { "option": "protocol", "value": "proxy", "carriers": [ "pojo" ], "javaType": "io.netty.buffer.ByteBuf" } ], "description": "The request body as the stream cache of Camel, which can be read many times; empty for a request without a body, such as a GET. The fields of a form POST are also headers. With disableStreamCache the Netty ByteBuf of the request, or an InputStream for a chunked request, read once" }, + "consumerReply": { "carriers": [ "null", "text", "bytes", "stream", "file", "value" ], "description": "The response body: text, bytes, a stream, a file, or a Netty ByteBuf or HttpResponse; no body sends 204. A Map or a POJO is written as its toString() and a List is not written at all: marshal it first. A failed exchange sends 500 with an empty body (muteException)" }, + "producerIn": { "carriers": [ "null", "text", "bytes", "stream", "file" ], "description": "The request body: text, bytes, a stream or a file, or a Netty ByteBuf or HttpRequest. A Map, a List or a POJO fails: marshal it first. Without the CamelHttpMethod header, no body sends a GET and a body a POST" }, + "producerOut": { "carriers": [ "bytes" ], "javaType": "byte[]", "dependsOn": [ "nettyHttpBinding", "sync" ], "byOption": [ { "option": "disableStreamCache", "value": "true", "carriers": [ "pojo", "stream" ] } ], "description": "The response body as a byte array, empty for a response without a body. With disableStreamCache the Netty ByteBuf of the response, or an InputStream for a chunked response; the ByteBuf is released when the exchange is done" } + }, "properties": { "protocol": { "index": 0, "kind": "path", "displayName": "Protocol", "group": "common", "label": "", "required": true, "type": "enum", "javaType": "java.lang.String", "enum": [ "http", "https", "proxy" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.netty.http.NettyHttpConfiguration", "configurationField": "configuration", "description": "The protocol to use which is either http, https or proxy (consumer only)." }, "host": { "index": 1, "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.netty.http.NettyHttpConfiguration", "configurationField": "configuration", "description": "The local hostname such as localhost, or 0.0.0.0 when being a consumer. The remote HTTP server hostname when using producer." }, diff --git a/components/camel-netty-http/src/main/docs/netty-http-component.adoc b/components/camel-netty-http/src/main/docs/netty-http-component.adoc index 4a8023084c2ae..2373c69dce3a2 100644 --- a/components/camel-netty-http/src/main/docs/netty-http-component.adoc +++ b/components/camel-netty-http/src/main/docs/netty-http-component.adoc @@ -20,17 +20,16 @@ component to simplify HTTP transport with xref:netty-component.adoc[Netty]. ==== *Stream* -Netty is stream-based, which means the input it receives is submitted to -Camel as a stream. That means you will only be able to read the content -of the stream *once*. If you find a situation where the message body appears to be empty, or -you need to access the data multiple times (eg: doing multicasting, or -redelivery error handling), you should use Stream caching or convert the -message body to a `String` which is safe to be re-read multiple times. - -Note also that Netty HTTP reads the entire stream into memory using +Netty HTTP reads the entire request into memory using `io.netty.handler.codec.http.HttpObjectAggregator` to build the entire -full http message. But the resulting message is still a stream-based -message that is readable once. +full http message. The consumer gives the request body as a Camel stream cache, +which can be read multiple times, and the producer gives the response body as a byte array. + +With `disableStreamCache=true` the body is the raw Netty `ByteBuf` instead (or an `InputStream` +for a chunked message), which you can only read *once*. If you find a situation where the +message body then appears to be empty, or you need to access the data multiple times (eg: doing +multicasting, or redelivery error handling), convert the message body to a `String` or a `byte[]` +which is safe to be re-read multiple times. ==== Maven users will need to add the following dependency to their `pom.xml` diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpEndpoint.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpEndpoint.java index 0bf479b51d6dc..1e9eb8548fc89 100644 --- a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpEndpoint.java +++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpEndpoint.java @@ -30,6 +30,9 @@ import org.apache.camel.http.base.OAuthHttpSecuritySupport; import org.apache.camel.http.base.OAuthProfileAwareHttpEndpoint; import org.apache.camel.http.base.cookie.CookieHandler; +import org.apache.camel.spi.BodyType; +import org.apache.camel.spi.BodyType.Carrier; +import org.apache.camel.spi.BodyTypes; import org.apache.camel.spi.HeaderFilterStrategy; import org.apache.camel.spi.HeaderFilterStrategyAware; import org.apache.camel.spi.Metadata; @@ -52,6 +55,36 @@ annotations = { "protocol=http", }) +@BodyTypes(consumerOut = @BodyType(value = Carrier.STREAM, + javaType = "org.apache.camel.component.netty.http.NettyChannelBufferStreamCache", + dependsOn = "nettyHttpBinding", + byOption = { + @BodyType.When(option = "disableStreamCache", value = "true", + carriers = { Carrier.POJO, Carrier.STREAM }), + @BodyType.When(option = "protocol", value = "proxy", carriers = Carrier.POJO, + javaType = "io.netty.buffer.ByteBuf") }, + description = "The request body as the stream cache of Camel, which can be read many" + + " times; empty for a request without a body, such as a GET. The fields of" + + " a form POST are also headers. With disableStreamCache the Netty ByteBuf" + + " of the request, or an InputStream for a chunked request, read once"), + consumerReply = @BodyType(value = { + Carrier.NULL, Carrier.TEXT, Carrier.BYTES, Carrier.STREAM, Carrier.FILE, + Carrier.VALUE }, + description = "The response body: text, bytes, a stream, a file, or a Netty ByteBuf or" + + " HttpResponse; no body sends 204. A Map or a POJO is written as its" + + " toString() and a List is not written at all: marshal it first. A" + + " failed exchange sends 500 with an empty body (muteException)"), + producerIn = @BodyType(value = { Carrier.NULL, Carrier.TEXT, Carrier.BYTES, Carrier.STREAM, Carrier.FILE }, + description = "The request body: text, bytes, a stream or a file, or a Netty ByteBuf or" + + " HttpRequest. A Map, a List or a POJO fails: marshal it first. Without" + + " the CamelHttpMethod header, no body sends a GET and a body a POST"), + producerOut = @BodyType(value = Carrier.BYTES, javaType = "byte[]", dependsOn = { "nettyHttpBinding", "sync" }, + byOption = @BodyType.When(option = "disableStreamCache", value = "true", + carriers = { Carrier.POJO, Carrier.STREAM }), + description = "The response body as a byte array, empty for a response without a body." + + " With disableStreamCache the Netty ByteBuf of the response, or an" + + " InputStream for a chunked response; the ByteBuf is released when the" + + " exchange is done")) public class NettyHttpEndpoint extends NettyEndpoint implements HeaderFilterStrategyAware, OAuthProfileAwareHttpEndpoint { private static final Logger LOG = LoggerFactory.getLogger(NettyHttpEndpoint.class); diff --git a/components/camel-netty/src/generated/resources/META-INF/org/apache/camel/component/netty/netty.json b/components/camel-netty/src/generated/resources/META-INF/org/apache/camel/component/netty/netty.json index a0a9ceba26e62..8212556f4fa25 100644 --- a/components/camel-netty/src/generated/resources/META-INF/org/apache/camel/component/netty/netty.json +++ b/components/camel-netty/src/generated/resources/META-INF/org/apache/camel/component/netty/netty.json @@ -115,6 +115,12 @@ "CamelNettyRequestTimeout": { "index": 10, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The read timeout.", "constantName": "org.apache.camel.component.netty.NettyConstants#NETTY_REQUEST_TIMEOUT" }, "CamelNettyChannel": { "index": 11, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "io.netty.channel.Channel", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The Netty Channel object.", "constantName": "org.apache.camel.component.netty.NettyConstants#NETTY_CHANNEL" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "text" ], "javaType": "java.lang.String", "dependsOn": [ "encoders", "decoders", "transferExchange" ], "byOption": [ { "option": "udpByteArrayCodec", "value": "true", "carriers": [ "bytes" ], "javaType": "byte[]" }, { "option": "allowDefaultCodec", "value": "false", "carriers": [ "pojo" ], "javaType": "io.netty.buffer.ByteBuf" } ], "description": "The data received as a String in the encoding (UTF-8 by default). Over TCP the default codec has no framing, so a message may arrive split over several exchanges; textline=true gives one line per exchange" }, + "consumerReply": { "carriers": [ "null", "text" ], "dependsOn": [ "encoders", "decoders", "transferExchange" ], "byOption": [ { "option": "textline", "value": "true", "carriers": [ "any" ] }, { "option": "udpByteArrayCodec", "value": "true", "carriers": [ "null", "bytes" ] }, { "option": "allowDefaultCodec", "value": "false", "carriers": [ "null", "pojo" ], "javaType": "io.netty.buffer.ByteBuf" } ], "description": "With sync=true (the default) the body the route ends with is written back: a String or a Netty ByteBuf. Bytes, a stream, a Map or a POJO cannot be written and the caller gets no reply: convert it to a String first (textline=true converts any body to a line of text). No body sends nothing and closes the connection (disconnectOnNoReply)" }, + "producerIn": { "carriers": [ "null", "text" ], "dependsOn": [ "encoders", "decoders", "transferExchange" ], "byOption": [ { "option": "textline", "value": "true", "carriers": [ "any" ] }, { "option": "udpByteArrayCodec", "value": "true", "carriers": [ "null", "bytes" ] }, { "option": "useByteBuf", "value": "true", "carriers": [ "null", "text", "bytes", "stream" ] }, { "option": "allowDefaultCodec", "value": "false", "carriers": [ "null", "pojo" ], "javaType": "io.netty.buffer.ByteBuf" } ], "description": "The data to send: a String, or a Netty ByteBuf over TCP. Bytes, a stream, a file, a Map or a POJO fail with an unsupported message type: convert it to a String first, or use textline=true, which converts any body to a line of text. No body sends nothing" }, + "producerOut": { "carriers": [ "text", "null" ], "javaType": "java.lang.String", "dependsOn": [ "encoders", "decoders", "transferExchange" ], "byOption": [ { "option": "sync", "value": "false", "carriers": [ "unchanged" ] }, { "option": "udpByteArrayCodec", "value": "true", "carriers": [ "bytes", "null" ], "javaType": "byte[]" }, { "option": "allowDefaultCodec", "value": "false", "carriers": [ "pojo", "null" ], "javaType": "io.netty.buffer.ByteBuf" } ], "description": "With sync=true (the default) the reply of the server as a String: over TCP without textline, the data of the first read. No body is not sent and stays null" } + }, "properties": { "protocol": { "index": 0, "kind": "path", "displayName": "Protocol", "group": "common", "label": "", "required": true, "type": "enum", "javaType": "java.lang.String", "enum": [ "tcp", "udp" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.netty.NettyConfiguration", "configurationField": "configuration", "description": "The protocol to use which can be tcp or udp" }, "host": { "index": 1, "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.netty.NettyConfiguration", "configurationField": "configuration", "description": "The hostname. For the consumer the hostname is localhost or 0.0.0.0. For the producer the hostname is the remote host to connect to." }, diff --git a/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyEndpoint.java b/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyEndpoint.java index 4b7b7a5af5eeb..1a713bf1e1766 100644 --- a/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyEndpoint.java +++ b/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyEndpoint.java @@ -32,6 +32,9 @@ import org.apache.camel.Message; 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; @@ -44,6 +47,59 @@ */ @UriEndpoint(firstVersion = "2.14.0", scheme = "netty", title = "Netty", syntax = "netty:protocol://host:port", category = { Category.NETWORKING }, headersClass = NettyConstants.class) +@BodyTypes(consumerOut = @BodyType(value = Carrier.TEXT, javaType = "java.lang.String", + dependsOn = { "encoders", "decoders", "transferExchange" }, + byOption = { + @BodyType.When(option = "udpByteArrayCodec", value = "true", + carriers = Carrier.BYTES, javaType = "byte[]"), + @BodyType.When(option = "allowDefaultCodec", value = "false", + carriers = Carrier.POJO, javaType = "io.netty.buffer.ByteBuf") }, + description = "The data received as a String in the encoding (UTF-8 by default). Over TCP" + + " the default codec has no framing, so a message may arrive split over" + + " several exchanges; textline=true gives one line per exchange"), + consumerReply = @BodyType(value = { Carrier.NULL, Carrier.TEXT }, + dependsOn = { "encoders", "decoders", "transferExchange" }, + byOption = { + @BodyType.When(option = "textline", value = "true", carriers = Carrier.ANY), + @BodyType.When(option = "udpByteArrayCodec", value = "true", + carriers = { Carrier.NULL, Carrier.BYTES }), + @BodyType.When(option = "allowDefaultCodec", value = "false", + carriers = { Carrier.NULL, Carrier.POJO }, + javaType = "io.netty.buffer.ByteBuf") }, + description = "With sync=true (the default) the body the route ends with is written" + + " back: a String or a Netty ByteBuf. Bytes, a stream, a Map or a POJO" + + " cannot be written and the caller gets no reply: convert it to a String" + + " first (textline=true converts any body to a line of text). No body" + + " sends nothing and closes the connection (disconnectOnNoReply)"), + producerIn = @BodyType(value = { Carrier.NULL, Carrier.TEXT }, + dependsOn = { "encoders", "decoders", "transferExchange" }, + byOption = { + @BodyType.When(option = "textline", value = "true", carriers = Carrier.ANY), + @BodyType.When(option = "udpByteArrayCodec", value = "true", + carriers = { Carrier.NULL, Carrier.BYTES }), + @BodyType.When(option = "useByteBuf", value = "true", + carriers = { + Carrier.NULL, Carrier.TEXT, Carrier.BYTES, + Carrier.STREAM }), + @BodyType.When(option = "allowDefaultCodec", value = "false", + carriers = { Carrier.NULL, Carrier.POJO }, + javaType = "io.netty.buffer.ByteBuf") }, + description = "The data to send: a String, or a Netty ByteBuf over TCP. Bytes, a stream, a" + + " file, a Map or a POJO fail with an unsupported message type: convert it" + + " to a String first, or use textline=true, which converts any body to a" + + " line of text. No body sends nothing"), + producerOut = @BodyType(value = { Carrier.TEXT, Carrier.NULL }, javaType = "java.lang.String", + dependsOn = { "encoders", "decoders", "transferExchange" }, + byOption = { + @BodyType.When(option = "sync", value = "false", carriers = Carrier.UNCHANGED), + @BodyType.When(option = "udpByteArrayCodec", value = "true", + carriers = { Carrier.BYTES, Carrier.NULL }, javaType = "byte[]"), + @BodyType.When(option = "allowDefaultCodec", value = "false", + carriers = { Carrier.POJO, Carrier.NULL }, + javaType = "io.netty.buffer.ByteBuf") }, + description = "With sync=true (the default) the reply of the server as a String: over TCP" + + " without textline, the data of the first read. No body is not sent and" + + " stays null")) public class NettyEndpoint extends DefaultEndpoint implements AsyncEndpoint, EndpointServiceLocation { @UriParam private NettyConfiguration configuration; diff --git a/components/camel-rest-postman/src/generated/resources/META-INF/org/apache/camel/component/rest/postman/rest-postman.json b/components/camel-rest-postman/src/generated/resources/META-INF/org/apache/camel/component/rest/postman/rest-postman.json index 22163e396f2d0..0738544a8514e 100644 --- a/components/camel-rest-postman/src/generated/resources/META-INF/org/apache/camel/component/rest/postman/rest-postman.json +++ b/components/camel-rest-postman/src/generated/resources/META-INF/org/apache/camel/component/rest/postman/rest-postman.json @@ -65,6 +65,12 @@ "CamelRestPostmanRequestCount": { "index": 3, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The number of requests executed when running a folder or a whole collection.", "constantName": "org.apache.camel.component.rest.postman.RestPostmanConstants#REQUEST_COUNT" }, "CamelRestPostmanFailedCount": { "index": 4, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The number of requests that failed when running a folder or a whole collection with runFailFast disabled.", "constantName": "org.apache.camel.component.rest.postman.RestPostmanConstants#FAILED_COUNT" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "stream", "bytes", "null", "map", "file" ], "dependsOn": [ "consumerComponentName" ], "description": "The request body as the HTTP consumer gives it (platform-http by default), null for a request without a body. It is handed to the direct route of the matched request (direct:); the route of this endpoint then has the body that route left, or the saved example as a String with missingRequest=mock" }, + "consumerReply": { "carriers": [ "null", "text", "bytes", "stream" ], "dependsOn": [ "consumerComponentName" ], "description": "The response body as the HTTP consumer writes it: text, bytes, a stream or no body. A Map or a List fails: marshal it first" }, + "producerIn": { "carriers": [ "null", "text", "bytes", "stream", "file" ], "dependsOn": [ "componentName" ], "description": "For a single request, the body sent, by the http component by default: text, bytes, a stream or a file. A Map, a List or a number fails: marshal it first. A folder or the whole collection (no requestId) sends the bodies written in the collection and ignores the message body" }, + "producerOut": { "carriers": [ "stream", "bytes", "null", "list" ], "dependsOn": [ "componentName" ], "description": "For a single request, the response body as the http component gives it: the stream cache, or null for a response without a body. For a folder or the whole collection (no requestId), a List of PostmanRunResult, one per request, with its status and response body" } + }, "properties": { "collectionSource": { "index": 0, "kind": "path", "displayName": "Collection Source", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "postman-collection.json", "description": "The Postman Collection to use. Either a resource URI of a Collection v2.1 JSON document (classpath:, file: or http:), or the uid of a collection to fetch from the Postman cloud, which requires postmanApiKey. Default value notice: By default loads the postman-collection.json file" }, "requestId": { "index": 1, "kind": "path", "displayName": "Request Id", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The request to invoke, identified by its id in the collection or by its slugified name, for example getUserById. Use a folder id to run every request in that folder, and leave it out to run the whole collection. Append a slash to force a folder match when a request and a folder share a name." }, diff --git a/components/camel-rest-postman/src/main/java/org/apache/camel/component/rest/postman/RestPostmanEndpoint.java b/components/camel-rest-postman/src/main/java/org/apache/camel/component/rest/postman/RestPostmanEndpoint.java index 82f2d5ad9d160..d6ef8f56486b8 100644 --- a/components/camel-rest-postman/src/main/java/org/apache/camel/component/rest/postman/RestPostmanEndpoint.java +++ b/components/camel-rest-postman/src/main/java/org/apache/camel/component/rest/postman/RestPostmanEndpoint.java @@ -49,6 +49,9 @@ import org.apache.camel.component.rest.postman.support.PostmanRequestBinding; import org.apache.camel.component.rest.postman.support.PostmanRequestIndex; import org.apache.camel.component.rest.postman.support.PostmanRequestMapper; +import org.apache.camel.spi.BodyType; +import org.apache.camel.spi.BodyType.Carrier; +import org.apache.camel.spi.BodyTypes; import org.apache.camel.spi.InternalProcessor; import org.apache.camel.spi.RestConfiguration; import org.apache.camel.spi.RestOpenApiConsumerFactory; @@ -73,6 +76,29 @@ @UriEndpoint(firstVersion = "4.23.0", scheme = "rest-postman", title = "REST Postman", syntax = "rest-postman:collectionSource#requestId", category = { Category.REST, Category.API }, headersClass = RestPostmanConstants.class) +@BodyTypes(consumerOut = @BodyType(value = { Carrier.STREAM, Carrier.BYTES, Carrier.NULL, Carrier.MAP, Carrier.FILE }, + dependsOn = "consumerComponentName", + description = "The request body as the HTTP consumer gives it (platform-http by default)," + + " null for a request without a body. It is handed to the direct route of" + + " the matched request (direct:); the route of this endpoint then" + + " has the body that route left, or the saved example as a String with" + + " missingRequest=mock"), + consumerReply = @BodyType(value = { Carrier.NULL, Carrier.TEXT, Carrier.BYTES, Carrier.STREAM }, + dependsOn = "consumerComponentName", + description = "The response body as the HTTP consumer writes it: text, bytes, a stream or" + + " no body. A Map or a List fails: marshal it first"), + producerIn = @BodyType(value = { Carrier.NULL, Carrier.TEXT, Carrier.BYTES, Carrier.STREAM, Carrier.FILE }, + dependsOn = "componentName", + description = "For a single request, the body sent, by the http component by default: text," + + " bytes, a stream or a file. A Map, a List or a number fails: marshal it" + + " first. A folder or the whole collection (no requestId) sends the bodies" + + " written in the collection and ignores the message body"), + producerOut = @BodyType(value = { Carrier.STREAM, Carrier.BYTES, Carrier.NULL, Carrier.LIST }, + dependsOn = "componentName", + description = "For a single request, the response body as the http component gives it: the" + + " stream cache, or null for a response without a body. For a folder or the" + + " whole collection (no requestId), a List of PostmanRunResult, one per" + + " request, with its status and response body")) public class RestPostmanEndpoint extends DefaultEndpoint { private static final Logger LOG = LoggerFactory.getLogger(RestPostmanEndpoint.class); diff --git a/components/camel-servlet/src/generated/resources/META-INF/org/apache/camel/component/servlet/servlet.json b/components/camel-servlet/src/generated/resources/META-INF/org/apache/camel/component/servlet/servlet.json index 9ae3cae07472c..e3ae521f3ffd7 100644 --- a/components/camel-servlet/src/generated/resources/META-INF/org/apache/camel/component/servlet/servlet.json +++ b/components/camel-servlet/src/generated/resources/META-INF/org/apache/camel/component/servlet/servlet.json @@ -38,6 +38,10 @@ "headerFilterStrategy": { "index": 10, "kind": "property", "displayName": "Header Filter Strategy", "group": "filter", "label": "filter", "required": false, "type": "object", "javaType": "org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "To use a custom org.apache.camel.spi.HeaderFilterStrategy to filter header to and from Camel message." }, "deserializationFilter": { "index": 11, "kind": "property", "displayName": "Deserialization Filter", "group": "security", "label": "advanced,security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets an ObjectInputFilter pattern (jdk.serialFilter syntax) applied when deserializing Java objects from requests or responses with Content-Type application\/x-java-serialized-object (only used when allowJavaSerializedObject or transferException is enabled). When not set, the JVM-wide jdk.serialFilter is used if present; otherwise a conservative default filter denying java.net. and otherwise allowing java., javax. and org.apache.camel. packages is applied." } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "stream", "null" ], "dependsOn": [ "transferException", "httpBinding" ], "description": "The request body as a stream cache, which can be read again (the raw stream, read once, with disableStreamCache); an empty one for a GET, null with Content-Length 0 or eagerCheckContentAvailable. The fields of a form are also headers; a multipart request is the raw multipart payload, or with attachmentMultipartBinding an empty body and its parts as attachments" }, + "consumerReply": { "carriers": [ "null", "text", "bytes", "stream", "file" ], "description": "The response body: text, bytes, a stream or a file. A Map, a List or a POJO is sent as an empty body (as its toString with chunked=false): marshal it first" } + }, "properties": { "contextPath": { "index": 0, "kind": "path", "displayName": "Context Path", "group": "consumer", "label": "consumer", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The context-path to use" }, "disableStreamCache": { "index": 1, "kind": "parameter", "displayName": "Disable Stream Cache", "group": "common", "label": "common", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Determines whether or not the raw input stream is cached or not. The Camel consumer (camel-servlet, camel-jetty etc.) will by default cache the input stream to support reading it multiple times to ensure it Camel can retrieve all data from the stream. However you can set this option to true when you for example need to access the raw stream, such as streaming it directly to a file or other persistent store. DefaultHttpBinding will copy the request input stream into a stream cache and put it into message body if this option is false to support reading the stream multiple times. If you use Servlet to bridge\/proxy an endpoint then consider enabling this option to improve performance, in case you do not need to read the message payload multiple times. The producer (camel-http) will by default cache the response body stream. If setting this option to true, then the producers will not cache the response body stream but use the response stream as-is (the stream can only be read once) as the message body." }, diff --git a/components/camel-servlet/src/main/docs/servlet-component.adoc b/components/camel-servlet/src/main/docs/servlet-component.adoc index 34940add1aabe..96ca7980cb456 100644 --- a/components/camel-servlet/src/main/docs/servlet-component.adoc +++ b/components/camel-servlet/src/main/docs/servlet-component.adoc @@ -35,8 +35,10 @@ for this component: *Stream* Servlet is stream-based, which means the input it receives is submitted -to Camel as a stream. That means you will only be able to read the -content of the stream *once*. If you find a situation where the message +to Camel as a stream. By default the consumer copies the request body into +a stream cache, which can be read more than once. With +`disableStreamCache=true` the body is the raw request stream, and you will +only be able to read the content of the stream *once*. If you find a situation where the message body appears to be empty, or you need to access the data multiple times (eg: doing multicasting, or redelivery error handling), you should use Stream caching or convert the message body to diff --git a/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletEndpoint.java b/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletEndpoint.java index d0bf271931f56..55ace69951291 100644 --- a/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletEndpoint.java +++ b/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletEndpoint.java @@ -29,6 +29,9 @@ import org.apache.camel.http.common.DefaultHttpBinding; import org.apache.camel.http.common.HttpBinding; import org.apache.camel.http.common.HttpCommonEndpoint; +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; @@ -42,6 +45,16 @@ @Metadata(excludeProperties = "httpUri", annotations = { "protocol=http", }) +@BodyTypes(consumerOut = @BodyType(value = { Carrier.STREAM, Carrier.NULL }, dependsOn = { "transferException", "httpBinding" }, + description = "The request body as a stream cache, which can be read again (the raw stream," + + " read once, with disableStreamCache); an empty one for a GET, null with" + + " Content-Length 0 or eagerCheckContentAvailable. The fields of a form are" + + " also headers; a multipart request is the raw multipart payload, or with" + + " attachmentMultipartBinding an empty body and its parts as attachments"), + consumerReply = @BodyType(value = { Carrier.NULL, Carrier.TEXT, Carrier.BYTES, Carrier.STREAM, Carrier.FILE }, + description = "The response body: text, bytes, a stream or a file. A Map, a List or a POJO" + + " is sent as an empty body (as its toString with chunked=false): marshal" + + " it first")) public class ServletEndpoint extends HttpCommonEndpoint implements OAuthProfileAwareHttpEndpoint { private HttpBinding binding; diff --git a/components/camel-spring-parent/camel-spring-ws/src/generated/resources/META-INF/org/apache/camel/component/spring/ws/spring-ws.json b/components/camel-spring-parent/camel-spring-ws/src/generated/resources/META-INF/org/apache/camel/component/spring/ws/spring-ws.json index 0e0b76f415b81..617e6cd8840f9 100644 --- a/components/camel-spring-parent/camel-spring-ws/src/generated/resources/META-INF/org/apache/camel/component/spring/ws/spring-ws.json +++ b/components/camel-spring-parent/camel-spring-ws/src/generated/resources/META-INF/org/apache/camel/component/spring/ws/spring-ws.json @@ -39,6 +39,12 @@ "CamelSpringWebserviceAddressingReplyTo": { "index": 5, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "java.net.URI", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Signifies the value for the replyTo response WS-Addressing ReplyTo header that is provided by the method. See org.springframework.ws.soap.addressing.server.annotation.Action annotation for more details.", "constantName": "org.apache.camel.component.spring.ws.SpringWebserviceConstants#SPRING_WS_ADDRESSING_PRODUCER_REPLY_TO" }, "breadcrumbId": { "index": 6, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The breadcrumb id.", "constantName": "org.apache.camel.component.spring.ws.SpringWebserviceConstants#BREADCRUMB_ID" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "pojo" ], "format": "xml", "description": "The payload of the SOAP body as a javax.xml.transform.Source (a DOMSource with the default SAAJ message factory); convertBodyTo String gives the XML. The SOAP header is in the CamelSpringWebserviceSoapHeader header" }, + "consumerReply": { "carriers": [ "text", "bytes", "stream", "pojo" ], "format": "xml", "description": "The response payload as XML: a String, bytes, a stream cache, a Source or a DOM Document. A body that does not convert to a Source, such as a Map, gives an empty SOAP body without an error" }, + "producerIn": { "carriers": [ "text", "bytes", "stream", "pojo" ], "format": "xml", "description": "The request payload as XML: a String, bytes, a stream cache, a Source or a DOM Document. No body, a File, a Map or a number fails: read or marshal it to XML first" }, + "producerOut": { "carriers": [ "pojo", "null" ], "format": "xml", "description": "The payload of the SOAP response as a javax.xml.transform.Source (a DOMSource with the default SAAJ message factory), null for an empty SOAP body; also with the InOnly pattern" } + }, "properties": { "type": { "index": 0, "kind": "path", "displayName": "Type", "group": "consumer", "label": "consumer", "required": false, "type": "enum", "javaType": "org.apache.camel.component.spring.ws.type.EndpointMappingType", "enum": [ "ROOT_QNAME", "ACTION", "TO", "SOAP_ACTION", "XPATHRESULT", "URI", "URI_PATH", "BEANNAME" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.spring.ws.SpringWebserviceConfiguration", "configurationField": "configuration", "description": "Endpoint mapping type if endpoint mapping is used. rootqname - Offers the option to map web service requests based on the qualified name of the root element contained in the message. soapaction - Used to map web service requests based on the SOAP action specified in the header of the message. uri - In order to map web service requests that target a specific URI. xpathresult - Used to map web service requests based on the evaluation of an XPath expression against the incoming message. The result of the evaluation should match the XPath result specified in the endpoint URI. beanname - Allows you to reference an org.apache.camel.component.spring.ws.bean.CamelEndpointDispatcher object in order to integrate with existing (legacy) endpoint mappings like PayloadRootQNameEndpointMapping, SoapActionEndpointMapping, etc" }, "lookupKey": { "index": 1, "kind": "path", "displayName": "Lookup Key", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.spring.ws.SpringWebserviceConfiguration", "configurationField": "configuration", "description": "Endpoint mapping key if endpoint mapping is used" }, diff --git a/components/camel-spring-parent/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceEndpoint.java b/components/camel-spring-parent/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceEndpoint.java index 1bd105e55216a..7c76729f34ff9 100644 --- a/components/camel-spring-parent/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceEndpoint.java +++ b/components/camel-spring-parent/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceEndpoint.java @@ -22,6 +22,9 @@ import org.apache.camel.ExchangePattern; 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.HeaderFilterStrategy; import org.apache.camel.spi.HeaderFilterStrategyAware; import org.apache.camel.spi.Metadata; @@ -38,6 +41,22 @@ @Metadata(annotations = { "protocol=http", }) +@BodyTypes(consumerOut = @BodyType(value = Carrier.POJO, format = "xml", + description = "The payload of the SOAP body as a javax.xml.transform.Source (a DOMSource with" + + " the default SAAJ message factory); convertBodyTo String gives the XML." + + " The SOAP header is in the CamelSpringWebserviceSoapHeader header"), + consumerReply = @BodyType(value = { Carrier.TEXT, Carrier.BYTES, Carrier.STREAM, Carrier.POJO }, format = "xml", + description = "The response payload as XML: a String, bytes, a stream cache, a Source or a" + + " DOM Document. A body that does not convert to a Source, such as a Map, gives" + + " an empty SOAP body without an error"), + producerIn = @BodyType(value = { Carrier.TEXT, Carrier.BYTES, Carrier.STREAM, Carrier.POJO }, format = "xml", + description = "The request payload as XML: a String, bytes, a stream cache, a Source or a DOM" + + " Document. No body, a File, a Map or a number fails: read or marshal it to" + + " XML first"), + producerOut = @BodyType(value = { Carrier.POJO, Carrier.NULL }, format = "xml", + description = "The payload of the SOAP response as a javax.xml.transform.Source (a DOMSource" + + " with the default SAAJ message factory), null for an empty SOAP body; also with" + + " the InOnly pattern")) public class SpringWebserviceEndpoint extends DefaultEndpoint implements HeaderFilterStrategyAware { @UriParam diff --git a/components/camel-undertow/src/generated/resources/META-INF/org/apache/camel/component/undertow/undertow.json b/components/camel-undertow/src/generated/resources/META-INF/org/apache/camel/component/undertow/undertow.json index f73e1978ba796..7117584b7be0f 100644 --- a/components/camel-undertow/src/generated/resources/META-INF/org/apache/camel/component/undertow/undertow.json +++ b/components/camel-undertow/src/generated/resources/META-INF/org/apache/camel/component/undertow/undertow.json @@ -54,6 +54,12 @@ "CamelHttpMethod": { "index": 13, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The http method", "constantName": "org.apache.camel.component.undertow.UndertowConstants#HTTP_METHOD" }, "Host": { "index": 14, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The host http header", "constantName": "org.apache.camel.component.undertow.UndertowConstants#HOST_STRING" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "bytes", "null", "map", "text" ], "dependsOn": [ "undertowHttpBinding" ], "byOption": [ { "option": "useStreaming", "value": "true", "carriers": [ "stream", "null", "map" ] } ], "description": "HTTP: the request body as a byte array for POST, PUT and PATCH, null for the other methods such as GET (a body they carry is dropped); a Map of the fields of a form or a multipart request, a file as a DataHandler (also an attachment). WebSocket: a String for a text message, a byte array for a binary one, null for the events of fireWebSocketChannelEvents" }, + "consumerReply": { "carriers": [ "null", "text", "bytes", "stream", "file" ], "description": "HTTP: the response body: text, bytes, a stream or a file. A Map, a List or a POJO fails with an empty 200 response: marshal it first. A WebSocket consumer does not reply: send to the peers with a producer" }, + "producerIn": { "carriers": [ "null", "text", "bytes", "stream", "file" ], "description": "HTTP: the request body: text, bytes, a stream or a file; without the CamelHttpMethod header, a query string or no body sends a GET, and a body a POST. A Map, a List or a POJO is sent as an empty body: marshal it first. WebSocket: text and bytes or a stream to the peers connected to this endpoint, other bodies as their toString; no body sends nothing" }, + "producerOut": { "carriers": [ "bytes", "unchanged" ], "byOption": [ { "option": "useStreaming", "value": "true", "carriers": [ "stream", "unchanged" ] } ], "description": "HTTP: the response body as a byte array, an empty one (not null) for a response without a body. WebSocket: the body is kept" } + }, "properties": { "httpURI": { "index": 0, "kind": "path", "displayName": "Http URI", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.net.URI", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The url of the HTTP endpoint to use." }, "useStreaming": { "index": 1, "kind": "parameter", "displayName": "Use Streaming", "group": "common", "label": "common", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "For HTTP endpoint: if true, text and binary messages will be wrapped as java.io.InputStream before they are passed to an Exchange; otherwise they will be passed as byte. For WebSocket endpoint: if true, text and binary messages will be wrapped as java.io.Reader and java.io.InputStream respectively before they are passed to an Exchange; otherwise they will be passed as String and byte respectively." }, diff --git a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowEndpoint.java b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowEndpoint.java index 24c23eecab29f..1e39571061f46 100644 --- a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowEndpoint.java +++ b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowEndpoint.java @@ -43,6 +43,9 @@ import org.apache.camel.http.base.OAuthHttpSecuritySupport; import org.apache.camel.http.base.OAuthProfileAwareHttpEndpoint; import org.apache.camel.http.base.cookie.CookieHandler; +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.HeaderFilterStrategy; import org.apache.camel.spi.HeaderFilterStrategyAware; @@ -64,6 +67,31 @@ */ @UriEndpoint(firstVersion = "2.16.0", scheme = "undertow", title = "Undertow", syntax = "undertow:httpURI", category = { Category.HTTP, Category.NETWORKING }, lenientProperties = true, headersClass = UndertowConstants.class) +@BodyTypes(consumerOut = @BodyType(value = { Carrier.BYTES, Carrier.NULL, Carrier.MAP, Carrier.TEXT }, + dependsOn = "undertowHttpBinding", + byOption = @BodyType.When(option = "useStreaming", value = "true", + carriers = { Carrier.STREAM, Carrier.NULL, Carrier.MAP }), + description = "HTTP: the request body as a byte array for POST, PUT and PATCH, null for" + + " the other methods such as GET (a body they carry is dropped); a Map of" + + " the fields of a form or a multipart request, a file as a DataHandler" + + " (also an attachment). WebSocket: a String for a text message, a byte" + + " array for a binary one, null for the events of" + + " fireWebSocketChannelEvents"), + consumerReply = @BodyType(value = { Carrier.NULL, Carrier.TEXT, Carrier.BYTES, Carrier.STREAM, Carrier.FILE }, + description = "HTTP: the response body: text, bytes, a stream or a file. A Map, a List or" + + " a POJO fails with an empty 200 response: marshal it first. A WebSocket" + + " consumer does not reply: send to the peers with a producer"), + producerIn = @BodyType(value = { Carrier.NULL, Carrier.TEXT, Carrier.BYTES, Carrier.STREAM, Carrier.FILE }, + description = "HTTP: the request body: text, bytes, a stream or a file; without the" + + " CamelHttpMethod header, a query string or no body sends a GET, and a body" + + " a POST. A Map, a List or a POJO is sent as an empty body: marshal it" + + " first. WebSocket: text and bytes or a stream to the peers connected to" + + " this endpoint, other bodies as their toString; no body sends nothing"), + producerOut = @BodyType(value = { Carrier.BYTES, Carrier.UNCHANGED }, + byOption = @BodyType.When(option = "useStreaming", value = "true", + carriers = { Carrier.STREAM, Carrier.UNCHANGED }), + description = "HTTP: the response body as a byte array, an empty one (not null) for a" + + " response without a body. WebSocket: the body is kept")) public class UndertowEndpoint extends DefaultEndpoint implements AsyncEndpoint, HeaderFilterStrategyAware, EndpointServiceLocation, OAuthProfileAwareHttpEndpoint { diff --git a/components/camel-vertx/camel-vertx-websocket/src/generated/resources/META-INF/org/apache/camel/component/vertx/websocket/vertx-websocket.json b/components/camel-vertx/camel-vertx-websocket/src/generated/resources/META-INF/org/apache/camel/component/vertx/websocket/vertx-websocket.json index ad282d35dc125..512c48a52067f 100644 --- a/components/camel-vertx/camel-vertx-websocket/src/generated/resources/META-INF/org/apache/camel/component/vertx/websocket/vertx-websocket.json +++ b/components/camel-vertx/camel-vertx-websocket/src/generated/resources/META-INF/org/apache/camel/component/vertx/websocket/vertx-websocket.json @@ -42,6 +42,11 @@ "CamelVertxWebsocket.remoteAddress": { "index": 2, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "io.vertx.core.net.SocketAddress", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The remote address.", "constantName": "org.apache.camel.component.vertx.websocket.VertxWebsocketConstants#REMOTE_ADDRESS" }, "CamelVertxWebsocket.event": { "index": 3, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "org.apache.camel.component.vertx.websocket.VertxWebsocketEvent", "enum": [ "CLOSE", "ERROR", "MESSAGE", "OPEN" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The WebSocket event that triggered the message exchange.", "constantName": "org.apache.camel.component.vertx.websocket.VertxWebsocketConstants#EVENT" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "text", "bytes" ], "byOption": [ { "option": "fireWebSocketConnectionEvents", "value": "true", "carriers": [ "text", "bytes", "pojo", "null" ] } ], "description": "The message received: a String for a text frame, a byte array for a binary frame. With fireWebSocketConnectionEvents=true, the OPEN event has the Vert.x ServerWebSocket as body and the CLOSE event no body: the CamelVertxWebsocket.event header tells them apart" }, + "producerIn": { "carriers": [ "null", "text", "bytes", "stream", "file" ], "description": "A String is sent as a text frame and a byte array as a binary frame; any other body is converted to a String and sent as a text frame, so a stream with binary content must be converted to bytes first, and a Map or a POJO is sent as its toString: marshal it first. No body sends nothing" }, + "producerOut": { "carriers": [ "unchanged" ] } + }, "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.vertx.websocket.VertxWebsocketConfiguration", "configurationField": "configuration", "description": "WebSocket hostname, such as localhost or a remote host when in client mode." }, "port": { "index": 1, "kind": "path", "displayName": "Port", "group": "common", "label": "", "required": true, "type": "integer", "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.websocket.VertxWebsocketConfiguration", "configurationField": "configuration", "description": "WebSocket port number to use." }, diff --git a/components/camel-vertx/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketEndpoint.java b/components/camel-vertx/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketEndpoint.java index 50a9a6991acba..6c7be52712fd3 100644 --- a/components/camel-vertx/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketEndpoint.java +++ b/components/camel-vertx/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketEndpoint.java @@ -38,6 +38,9 @@ import org.apache.camel.Processor; import org.apache.camel.Producer; import org.apache.camel.component.vertx.common.VertxHelper; +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.HeaderFilterStrategy; import org.apache.camel.spi.HeaderFilterStrategyAware; @@ -58,6 +61,21 @@ @UriEndpoint(firstVersion = "3.5.0", scheme = "vertx-websocket", title = "Vert.x WebSocket", syntax = "vertx-websocket:host:port/path", category = { Category.HTTP, Category.NETWORKING }, headersClass = VertxWebsocketConstants.class, lenientProperties = true) +@BodyTypes(consumerOut = @BodyType(value = { Carrier.TEXT, Carrier.BYTES }, + byOption = @BodyType.When(option = "fireWebSocketConnectionEvents", value = "true", + carriers = { + Carrier.TEXT, Carrier.BYTES, Carrier.POJO, + Carrier.NULL }), + description = "The message received: a String for a text frame, a byte array for a binary" + + " frame. With fireWebSocketConnectionEvents=true, the OPEN event has the" + + " Vert.x ServerWebSocket as body and the CLOSE event no body: the" + + " CamelVertxWebsocket.event header tells them apart"), + producerIn = @BodyType(value = { Carrier.NULL, Carrier.TEXT, Carrier.BYTES, Carrier.STREAM, Carrier.FILE }, + description = "A String is sent as a text frame and a byte array as a binary frame; any other" + + " body is converted to a String and sent as a text frame, so a stream with" + + " binary content must be converted to bytes first, and a Map or a POJO is sent" + + " as its toString: marshal it first. No body sends nothing"), + producerOut = @BodyType(Carrier.UNCHANGED)) public class VertxWebsocketEndpoint extends DefaultEndpoint implements EndpointServiceLocation, HeaderFilterStrategyAware { private static final Logger LOG = LoggerFactory.getLogger(VertxWebsocketEndpoint.class); diff --git a/components/camel-webhook/src/generated/resources/META-INF/org/apache/camel/component/webhook/webhook.json b/components/camel-webhook/src/generated/resources/META-INF/org/apache/camel/component/webhook/webhook.json index 8aca390e6cabe..ae8bcf2dd4347 100644 --- a/components/camel-webhook/src/generated/resources/META-INF/org/apache/camel/component/webhook/webhook.json +++ b/components/camel-webhook/src/generated/resources/META-INF/org/apache/camel/component/webhook/webhook.json @@ -34,6 +34,10 @@ "autowiredEnabled": { "index": 6, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." }, "configuration": { "index": 7, "kind": "property", "displayName": "Configuration", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.webhook.WebhookConfiguration", "deprecated": false, "autowired": false, "secret": false, "description": "Set the default configuration for the webhook meta-component." } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "unknown" ], "description": "The body the webhook handler of the delegate component (endpointUri) makes of the HTTP request: the same body as its polling consumer, such as an IncomingMessage (or another update) for Telegram, an Event for ClickUp, or the JSON as a String for WhatsApp" }, + "consumerReply": { "carriers": [ "any" ], "description": "The delegate component sets the HTTP response body itself after the route: Telegram and ClickUp reply with an empty body, WhatsApp with the request content, whatever body the route ends with" } + }, "properties": { "endpointUri": { "index": 0, "kind": "path", "displayName": "Endpoint Uri", "group": "consumer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.webhook.WebhookConfiguration", "configurationField": "configuration", "description": "The delegate uri. Must belong to a component that supports webhooks." }, "webhookAutoRegister": { "index": 1, "kind": "parameter", "displayName": "Webhook Auto Register", "group": "consumer", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.webhook.WebhookConfiguration", "configurationField": "configuration", "description": "Automatically register the webhook at startup and unregister it on shutdown." }, diff --git a/components/camel-webhook/src/main/java/org/apache/camel/component/webhook/WebhookEndpoint.java b/components/camel-webhook/src/main/java/org/apache/camel/component/webhook/WebhookEndpoint.java index 912f91f9076f7..7ea47abbc6ab4 100644 --- a/components/camel-webhook/src/main/java/org/apache/camel/component/webhook/WebhookEndpoint.java +++ b/components/camel-webhook/src/main/java/org/apache/camel/component/webhook/WebhookEndpoint.java @@ -24,6 +24,9 @@ import org.apache.camel.Endpoint; 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.Metadata; import org.apache.camel.spi.RestConsumerFactory; import org.apache.camel.spi.UriEndpoint; @@ -41,6 +44,15 @@ @Metadata(annotations = { "protocol=http", }) +@BodyTypes(consumerOut = @BodyType(value = Carrier.UNKNOWN, + description = "The body the webhook handler of the delegate component (endpointUri) makes of" + + " the HTTP request: the same body as its polling consumer, such as an" + + " IncomingMessage (or another update) for Telegram, an Event for ClickUp, or the JSON as a String" + + " for WhatsApp"), + consumerReply = @BodyType(value = Carrier.ANY, + description = "The delegate component sets the HTTP response body itself after the route:" + + " Telegram and ClickUp reply with an empty body, WhatsApp with the request" + + " content, whatever body the route ends with")) public class WebhookEndpoint extends DefaultEndpoint implements DelegateEndpoint, AfterPropertiesConfigured { private static final Logger LOG = LoggerFactory.getLogger(WebhookEndpoint.class);