You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by pp...@apache.org on 2023/06/12 21:30:57 UTC

[camel] 03/07: [3.20.x] Backports (#10035)

This is an automated email from the ASF dual-hosted git repository.

ppalaga pushed a commit to branch camel-3.x
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 0d9478cb90b2b4d2f274e3da668448a65b6b4ca1
Author: Peter Palaga <pp...@redhat.com>
AuthorDate: Tue May 9 17:43:50 2023 +0200

    [3.20.x] Backports (#10035)
    
    * fix up MTOM POJO dataformat doc for camel-cxf-soap
    
    * [CAMEL-19129] Improve Camel CXF documentation
    
    * [CAMEL-19129] Reorganize sections in Camel CXF
    
    * [CAMEL-19129] Add simple example of CXF service implementation with Camel
    
    * CXF docs polish - Fixes from review
    
    ---------
    
    Co-authored-by: Freeman Fang <fr...@gmail.com>
    Co-authored-by: Lukas Lowinger <ll...@redhat.com>
---
 .../src/main/docs/cxf-component.adoc               | 1250 ++++++++++----------
 1 file changed, 606 insertions(+), 644 deletions(-)

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 59d4cfca254..7835af8d76d 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
@@ -30,7 +30,7 @@ for this component:
 ------------------------------------------------------------
 <dependency>
     <groupId>org.apache.camel</groupId>
-    <artifactId>camel-cxf</artifactId>
+    <artifactId>camel-cxf-soap</artifactId>
     <version>x.x.x</version>
     <!-- use the same version as your Camel core version -->
 </dependency>
@@ -104,11 +104,11 @@ handlers are supported.
 message configuration in the CXF endpoint is applied. Only Protocol
 JAX-WS handler is supported. Logical JAX-WS handler is not supported.
 
-|`MESSAGE` |`MESSAGE` mode provides the raw message stream that is received from the transport layer.
+|`RAW` |`RAW` mode provides the raw message stream that is received from the transport layer.
 It is not possible to touch or change the stream, some of the CXF
 interceptors will be removed if you are using this kind of DataFormat, so
 you can't see any soap headers after the camel-cxf consumer. JAX-WS
-handler is not supported.
+handler is not supported. Note that `RAW` mode is equivalent to deprecated `MESSAGE` mode.
 
 |`CXF_MESSAGE` |`CXF_MESSAGE` allows for invoking the full
 capabilities of CXF interceptors by converting the message from the
@@ -120,520 +120,139 @@ exchange property, `CamelCXFDataFormat`. The exchange key constant is
 defined in
 `org.apache.camel.component.cxf.common.message.CxfConstants.DATA_FORMAT_PROPERTY`.
 
-[#cxf-loggingout-interceptor-in-message-mode]
-=== How to enable CXF's LoggingOutInterceptor in MESSAGE mode
-
-CXF's `LoggingOutInterceptor` outputs outbound message that goes on the
-wire to logging system (Java Util Logging). Since the
-`LoggingOutInterceptor` is in `PRE_STREAM` phase (but `PRE_STREAM` phase
-is removed in `MESSAGE` mode), you have to configure
-`LoggingOutInterceptor` to be run during the `WRITE` phase. The
-following is an example.
-
-[source,xml]
--------------------------------------------------------------------------------------------------------
-<bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor">
-    <!--  it really should have been user-prestream but CXF does have such phase! -->
-    <constructor-arg value="target/write"/>
-</bean>
-
-<cxf:cxfEndpoint id="serviceEndpoint" address="http://localhost:${CXFTestSupport.port2}/LoggingInterceptorInMessageModeTest/helloworld"
-    serviceClass="org.apache.camel.component.cxf.HelloService">
-    <cxf:outInterceptors>
-        <ref bean="loggingOutInterceptor"/>
-    </cxf:outInterceptors>
-    <cxf:properties>
-        <entry key="dataFormat" value="RAW"/>
-    </cxf:properties>
-</cxf:cxfEndpoint>
--------------------------------------------------------------------------------------------------------
+== How to create simple CXF service with POJO data format
 
-=== Description of relayHeaders option
+Having simple java web service interface
 
-There are _in-band_ and _out-of-band_ on-the-wire headers from the
-perspective of a JAXWS WSDL-first developer.
 
-The _in-band_ headers are headers that are explicitly defined as part of
-the WSDL binding contract for an endpoint such as SOAP headers.
+[source,java]
+----
+package org.apache.camel.component.cxf.soap.server;
 
-The _out-of-band_ headers are headers that are serialized over the wire,
-but are not explicitly part of the WSDL binding contract.
+@WebService(targetNamespace = "http://server.soap.cxf.component.camel.apache.org/", name = "EchoService")
+public interface EchoService {
 
-Headers relaying/filtering is bi-directional.
+    String echo(String text);
+}
+----
 
-When a route has a CXF endpoint and the developer needs to have
-on-the-wire headers, such as SOAP headers, be relayed along the route to
-be consumed say by another JAXWS endpoint, then `relayHeaders` should be
-set to `true`, which is the default value.
+and implementation
 
+[source,java]
+----
 
-=== Available only in POJO mode
+package org.apache.camel.component.cxf.soap.server;
 
-The `relayHeaders=true` expresses an intent to relay the headers. The
-actual decision on whether a given header is relayed is delegated to a
-pluggable instance that implements the `MessageHeadersRelay` interface.
-A concrete implementation of `MessageHeadersRelay` will be consulted to
-decide if a header needs to be relayed or not. There is already an
-implementation of `SoapMessageHeadersRelay` which binds itself to
-well-known SOAP name spaces. Currently only out-of-band headers are
-filtered, and in-band headers will always be relayed when
-`relayHeaders=true`. If there is a header on the wire whose name space
-is unknown to the runtime, then a fall back `DefaultMessageHeadersRelay`
-will be used, which simply allows all headers to be relayed.
+@WebService(name = "EchoService", serviceName = "EchoService", targetNamespace = "http://server.soap.cxf.component.camel.apache.org/")
+public class EchoServiceImpl implements EchoService {
 
-The `relayHeaders=false` setting specifies that all headers in-band and
-out-of-band should be dropped.
+    @Override
+    public String echo(String text) {
+        return text;
+    }
 
-You can plugin your own `MessageHeadersRelay` implementations overriding
-or adding additional ones to the list of relays. In order to override a
-preloaded relay instance just make sure that your `MessageHeadersRelay`
-implementation services the same name spaces as the one you looking to
-override. Also note, that the overriding relay has to service all of the
-name spaces as the one you looking to override, or else a runtime
-exception on route start up will be thrown as this would introduce an
-ambiguity in name spaces to relay instance mappings.
+}
+----
 
-[source,xml]
--------------------------------------------------------------------------------------------------------
-<cxf:cxfEndpoint ...>
-   <cxf:properties>
-     <entry key="org.apache.camel.cxf.message.headers.relays">
-       <list>
-         <ref bean="customHeadersRelay"/>
-       </list>
-     </entry>
-   </cxf:properties>
- </cxf:cxfEndpoint>
- <bean id="customHeadersRelay" class="org.apache.camel.component.cxf.soap.headers.CustomHeadersRelay"/>
--------------------------------------------------------------------------------------------------------
+We can then create the simplest CXF service (note we didn't specify the `POJO` mode, as it is the default mode):
 
-Take a look at the tests that show how you'd be able to relay/drop
-headers here:
+[source,java]
+----
+    from("cxf:echoServiceResponseFromImpl?serviceClass=org.apache.camel.component.cxf.soap.server.EchoServiceImpl&address=/echo-impl")// no body set here; the response comes from EchoServiceImpl
+                .log("${body}");
+----
 
-https://github.com/apache/camel/blob/main/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/soap/headers/CxfMessageHeadersRelayTest.java[https://github.com/apache/camel/blob/main/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/soap/headers/CxfMessageHeadersRelayTest.java]
+For more complicated implementation of the service (more "Camel way"), we can set the body from the route instead: 
 
-* `POJO` and `PAYLOAD` modes are supported. In `POJO` mode, only
-out-of-band message headers are available for filtering as the in-band
-headers have been processed and removed from header list by CXF. The
-in-band headers are incorporated into the `MessageContentList` in POJO
-mode. The `camel-cxf` component does make any attempt to remove the
-in-band headers from the `MessageContentList`. If filtering of in-band
-headers is required, please use `PAYLOAD` mode or plug in a (pretty
-straightforward) CXF interceptor/JAXWS Handler to the CXF endpoint.
-* The Message Header Relay mechanism has been merged into
-`CxfHeaderFilterStrategy`. The `relayHeaders` option, its semantics, and
-default value remain the same, but it is a property of
-`CxfHeaderFilterStrategy`.
- Here is an example of configuring it.
+[source,java]
+----
+    from("cxf:echoServiceResponseFromRoute?serviceClass=org.apache.camel.component.cxf.soap.server.EchoServiceImpl&address=/echo-route")
+                .setBody(exchange -> exchange.getMessage().getBody(String.class) + " from Camel route");
+----
 
-[source,xml]
--------------------------------------------------------------------------------------------------------
-<bean id="dropAllMessageHeadersStrategy" class="org.apache.camel.component.cxf.transport.header.CxfHeaderFilterStrategy">
 
-    <!--  Set relayHeaders to false to drop all SOAP headers -->
-    <property name="relayHeaders" value="false"/>
+== How to consume a message from a camel-cxf endpoint in POJO data format
 
-</bean>
--------------------------------------------------------------------------------------------------------
+The `camel-cxf` endpoint consumer POJO data format is based on the
+http://cxf.apache.org/docs/invokers.html[CXF invoker], so the
+message header has a property with the name of
+`CxfConstants.OPERATION_NAME` and the message body is a list of the SEI
+method parameters.
 
-Then, your endpoint can reference the `CxfHeaderFilterStrategy`.
+Consider the https://github.com/apache/camel/blob/main/components/camel-cxf/camel-cxf-soap/src/test/java/org/apache/camel/wsdl_first/PersonProcessor.java[PersonProcessor] example code:
 
-[source,xml]
--------------------------------------------------------------------------------------------------------
-<route>
-    <from uri="cxf:bean:routerNoRelayEndpoint?headerFilterStrategy=#dropAllMessageHeadersStrategy"/>
-    <to uri="cxf:bean:serviceNoRelayEndpoint?headerFilterStrategy=#dropAllMessageHeadersStrategy"/>
-</route>
--------------------------------------------------------------------------------------------------------
+[source,java]
+----
+public class PersonProcessor implements Processor {
 
-* The `MessageHeadersRelay` interface has changed slightly and has been
-renamed to `MessageHeaderFilter`. It is a property of
-`CxfHeaderFilterStrategy`. Here is an example of configuring user
-defined Message Header Filters:
+    private static final Logger LOG = LoggerFactory.getLogger(PersonProcessor.class);
 
-[source,xml]
--------------------------------------------------------------------------------------------------------
-<bean id="customMessageFilterStrategy" class="org.apache.camel.component.cxf.transport.header.CxfHeaderFilterStrategy">
-    <property name="messageHeaderFilters">
-        <list>
-            <!--  SoapMessageHeaderFilter is the built in filter.  It can be removed by omitting it. -->
-            <bean class="org.apache.camel.component.cxf.common.header.SoapMessageHeaderFilter"/>
+    @Override
+    @SuppressWarnings("unchecked")
+    public void process(Exchange exchange) throws Exception {
+        LOG.info("processing exchange in camel");
 
-            <!--  Add custom filter here -->
-            <bean class="org.apache.camel.component.cxf.soap.headers.CustomHeaderFilter"/>
-        </list>
-    </property>
-</bean>
--------------------------------------------------------------------------------------------------------
+        BindingOperationInfo boi = (BindingOperationInfo) exchange.getProperty(BindingOperationInfo.class.getName());
+        if (boi != null) {
+            LOG.info("boi.isUnwrapped" + boi.isUnwrapped());
+        }
+        // Get the parameters list which element is the holder.
+        MessageContentsList msgList = (MessageContentsList) exchange.getIn().getBody();
+        Holder<String> personId = (Holder<String>) msgList.get(0);
+        Holder<String> ssn = (Holder<String>) msgList.get(1);
+        Holder<String> name = (Holder<String>) msgList.get(2);
 
-* In addition to `relayHeaders`, the following properties can be
-configured in `CxfHeaderFilterStrategy`.
+        if (personId.value == null || personId.value.length() == 0) {
+            LOG.info("person id 123, so throwing exception");
+            // Try to throw out the soap fault message
+            org.apache.camel.wsdl_first.types.UnknownPersonFault personFault
+                    = new org.apache.camel.wsdl_first.types.UnknownPersonFault();
+            personFault.setPersonId("");
+            org.apache.camel.wsdl_first.UnknownPersonFault fault
+                    = new org.apache.camel.wsdl_first.UnknownPersonFault("Get the null value of person name", personFault);
+            exchange.getMessage().setBody(fault);
+            return;
+        }
 
-[width="100%",cols="10%,10%,80%",options="header",]
-|=======================================================================
-|Name |Required |Description
-|`relayHeaders` |No |All message headers will be processed by Message Header Filters
- _Type_: `boolean`
- _Default_: `true`
+        name.value = "Bonjour";
+        ssn.value = "123";
+        LOG.info("setting Bonjour as the response");
+        // Set the response message, first element is the return value of the operation,
+        // the others are the holders of method parameters
+        exchange.getMessage().setBody(new Object[] { null, personId, ssn, name });
+    }
 
-|`relayAllMessageHeaders` | No |All message headers will be propagated (without processing by Message
-Header Filters)
- _Type_: `boolean`
- _Default_: `false`
+}
+----
 
-|`allowFilterNamespaceClash` |No |If two filters overlap in activation namespace, the property control how
-it should be handled. If the value is `true`, last one wins. If the
-value is `false`, it will throw an exception
- _Type_: `boolean`
- _Default_: `false`
-|=======================================================================
+== How to prepare the message for the camel-cxf endpoint in POJO data format
 
-== Configure the CXF endpoints with Spring
+The `camel-cxf` endpoint producer is based on the
+https://github.com/apache/cxf/blob/master/core/src/main/java/org/apache/cxf/endpoint/Client.java[CXF
+client API]. First you need to specify the operation name in the message
+header, then add the method parameters to a list, and initialize the
+message with this parameter list. The response message's body is a
+messageContentsList, you can get the result from that list.
 
-You can configure the CXF endpoint with the Spring configuration file
-shown below, and you can also embed the endpoint into the `camelContext`
-tags. When you are invoking the service endpoint, you can set the
-`operationName` and `operationNamespace` headers to explicitly state
-which operation you are calling.
+If you don't specify the operation name in the message header,
+`CxfProducer` will try to use the `defaultOperationName` from
+`CxfEndpoint`, if there is no `defaultOperationName` set on
+`CxfEndpoint`, it will pick up the first operationName from the Operation
+list.
 
-[source,xml]
-----------------------------------------------------------------------------------------------------------------
-<beans xmlns="http://www.springframework.org/schema/beans"
-        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-        xmlns:cxf="http://camel.apache.org/schema/cxf"
-        xsi:schemaLocation="
-        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
-        http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd
-        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
-     <cxf:cxfEndpoint id="routerEndpoint" address="http://localhost:9003/CamelContext/RouterPort"
-            serviceClass="org.apache.hello_world_soap_http.GreeterImpl"/>
-     <cxf:cxfEndpoint id="serviceEndpoint" address="http://localhost:9000/SoapContext/SoapPort"
-            wsdlURL="testutils/hello_world.wsdl"
-            serviceClass="org.apache.hello_world_soap_http.Greeter"
-            endpointName="s:SoapPort"
-            serviceName="s:SOAPService"
-        xmlns:s="http://apache.org/hello_world_soap_http" />
-     <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
-       <route>
-         <from uri="cxf:bean:routerEndpoint" />
-         <to uri="cxf:bean:serviceEndpoint" />
-       </route>
-    </camelContext>
-  </beans>
-----------------------------------------------------------------------------------------------------------------
+If you want to get the object array from the message body, you can get
+the body using `message.getBody(Object[].class)`, as shown in https://github.com/apache/camel/blob/main/components/camel-cxf/camel-cxf-soap/src/test/java/org/apache/camel/component/cxf/jaxws/CxfProducerRouterTest.java#L117[CxfProducerRouterTest.testInvokingSimpleServerWithParams]:
 
-Be sure to include the JAX-WS `schemaLocation` attribute specified on
-the root beans element. This allows CXF to validate the file and is
-required. Also note the namespace declarations at the end of the
-`<cxf:cxfEndpoint/>` tag. These declarations are required because the combined `\{namespace}localName` syntax is presently not supported for this tag's
-attribute values.
+[source,java]
+----
+Exchange senderExchange = new DefaultExchange(context, ExchangePattern.InOut);
+final List<String> params = new ArrayList<>();
+// Prepare the request message for the camel-cxf procedure
+params.add(TEST_MESSAGE);
+senderExchange.getIn().setBody(params);
+senderExchange.getIn().setHeader(CxfConstants.OPERATION_NAME, ECHO_OPERATION);
 
-The `cxf:cxfEndpoint` element supports many additional attributes:
-
-[width="100%",cols="50%,50%",options="header",]
-|=======================================================================
-|Name |Value
-
-|`PortName` |The endpoint name this service is implementing, it maps to the
-`wsdl:port@name`. In the format of `ns:PORT_NAME` where `ns` is a
-namespace prefix valid at this scope.
-
-|`serviceName` |The service name this service is implementing, it maps to the
-`wsdl:service@name`. In the format of `ns:SERVICE_NAME` where `ns` is a
-namespace prefix valid at this scope.
-
-|`wsdlURL` |The location of the WSDL. Can be on the classpath, file system, or be
-hosted remotely.
-
-|`bindingId` |The `bindingId` for the service model to use.
-
-|`address` |The service publish address.
-
-|`bus` |The bus name that will be used in the JAX-WS endpoint.
-
-|`serviceClass` |The class name of the SEI (Service Endpoint Interface) class which could
-have JSR181 annotation or not.
-|=======================================================================
-
-It also supports many child elements:
-
-[width="100%",cols="50%,50%",options="header",]
-|=======================================================================
-|Name |Value
-
-|`cxf:inInterceptors` |The incoming interceptors for this endpoint. A list of `<bean>` or
-`<ref>`.
-
-|`cxf:inFaultInterceptors` |The incoming fault interceptors for this endpoint. A list of `<bean>` or
-`<ref>`.
-
-|`cxf:outInterceptors` |The outgoing interceptors for this endpoint. A list of `<bean>` or
-`<ref>`.
-
-|`cxf:outFaultInterceptors` |The outgoing fault interceptors for this endpoint. A list of `<bean>` or
-`<ref>`.
-
-|`cxf:properties` | A properties map which should be supplied to the JAX-WS endpoint. See
-below.
-
-|`cxf:handlers` |A JAX-WS handler list which should be supplied to the JAX-WS endpoint.
-See below.
-
-|`cxf:dataBinding` |You can specify the which `DataBinding` will be use in the endpoint.
-This can be supplied using the Spring `<bean class="MyDataBinding"/>`
-syntax.
-
-|`cxf:binding` |You can specify the `BindingFactory` for this endpoint to use. This can
-be supplied using the Spring `<bean class="MyBindingFactory"/>` syntax.
-
-|`cxf:features` |The features that hold the interceptors for this endpoint. A list of
-beans or refs
-
-|`cxf:schemaLocations` |The schema locations for endpoint to use. A list of schemaLocations
-
-|`cxf:serviceFactory` |The service factory for this endpoint to use. This can be supplied using
-the Spring `<bean class="MyServiceFactory"/>` syntax
-|=======================================================================
-
-You can find more advanced examples that show how to provide
-interceptors, properties and handlers on the CXF
-http://cxf.apache.org/docs/jax-ws-configuration.html[JAX-WS
-Configuration page].
-
-[NOTE]
-====
-You can use cxf:properties to set the camel-cxf endpoint's dataFormat
-and setDefaultBus properties from spring configuration file.
-
-[source,xml]
--------------------------------------------------------------------------
-<cxf:cxfEndpoint id="testEndpoint" address="http://localhost:9000/router"
-     serviceClass="org.apache.camel.component.cxf.HelloService"
-     endpointName="s:PortName"
-     serviceName="s:ServiceName"
-     xmlns:s="http://www.example.com/test">
-     <cxf:properties>
-       <entry key="dataFormat" value="RAW"/>
-       <entry key="setDefaultBus" value="true"/>
-     </cxf:properties>
-   </cxf:cxfEndpoint>
--------------------------------------------------------------------------
-====
-
-== Configuring the CXF Endpoints with Apache Aries Blueprint
-
-The component is capable of utilizing aries blueprint
-dependency injection for your CXF endpoints.
- The schema utilized is very similar to the spring schema so the
-transition is fairly transparent.
-
-Example
-
-[source,xml]
-------------------------------------------------------------------------------------------------------------------------------------
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
-           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-           xmlns:camel-cxf="http://camel.apache.org/schema/blueprint/cxf"
-           xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
-
-      <camel-cxf:cxfEndpoint id="routerEndpoint"
-                     address="http://localhost:9001/router"
-                     serviceClass="org.apache.servicemix.examples.cxf.HelloWorld">
-        <camel-cxf:properties>
-            <entry key="dataFormat" value="RAW"/>
-        </camel-cxf:properties>
-     </camel-cxf:cxfEndpoint>
-
-     <camel-cxf:cxfEndpoint id="serviceEndpoint"
-            address="http://localhost:9000/SoapContext/SoapPort"
-                     serviceClass="org.apache.servicemix.examples.cxf.HelloWorld">
-    </camel-cxf:cxfEndpoint>
-
-    <camelContext xmlns="http://camel.apache.org/schema/blueprint">
-        <route>
-            <from uri="routerEndpoint"/>
-            <to uri="log:request"/>
-        </route>
-    </camelContext>
-
-</blueprint>
-------------------------------------------------------------------------------------------------------------------------------------
-
-Currently the endpoint element is the first supported CXF
-namespacehandler.
-
-You can also use the bean references just as in spring
-
-[source,xml]
-----------------------------------------------------------------------------------------------------------------
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
-           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-           xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0"
-           xmlns:jaxws="http://cxf.apache.org/blueprint/jaxws"
-           xmlns:cxf="http://cxf.apache.org/blueprint/core"
-           xmlns:camel="http://camel.apache.org/schema/blueprint"
-           xmlns:camelcxf="http://camel.apache.org/schema/blueprint/cxf"
-           xsi:schemaLocation="
-             http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
-             http://cxf.apache.org/blueprint/jaxws http://cxf.apache.org/schemas/blueprint/jaxws.xsd
-             http://cxf.apache.org/blueprint/core http://cxf.apache.org/schemas/blueprint/core.xsd
-             ">
-
-    <camelcxf:cxfEndpoint id="reportIncident"
-                     address="/camel-example-cxf-blueprint/webservices/incident"
-                     wsdlURL="META-INF/wsdl/report_incident.wsdl"
-                     serviceClass="org.apache.camel.example.reportincident.ReportIncidentEndpoint">
-    </camelcxf:cxfEndpoint>
-
-    <bean id="reportIncidentRoutes" class="org.apache.camel.example.reportincident.ReportIncidentRoutes" />
-
-    <camelContext xmlns="http://camel.apache.org/schema/blueprint">
-        <routeBuilder ref="reportIncidentRoutes"/>
-    </camelContext>
-
-</blueprint>
-----------------------------------------------------------------------------------------------------------------
-
-== How to make the camel-cxf component use log4j instead of java.util.logging
-
-CXF's default logger is `java.util.logging`. If you want to change it to
-log4j, proceed as follows. Create a file, in the classpath, named
-`META-INF/cxf/org.apache.cxf.logger`. This file should contain the
-fully-qualified name of the class,
-`org.apache.cxf.common.logging.Log4jLogger`, with no comments, on a
-single line.
-
-== How to let camel-cxf response start with xml processing instruction
-
-If you are using some SOAP client such as PHP, you will get this kind of
-error, because CXF doesn't add the XML processing instruction
-`<?xml version="1.0" encoding="utf-8"?>`:
-
----------------------------------------------------------------------------------------
-Error:sendSms: SoapFault exception: [Client] looks like we got no XML document in [...]
----------------------------------------------------------------------------------------
-
-To resolve this issue, you just need to tell StaxOutInterceptor to
-write the XML start document for you, as in the https://github.com/apache/camel/blob/main/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/WriteXmlDeclarationInterceptor.java[WriteXmlDeclarationInterceptor] below:
-
-[source,java]
-----
-public class WriteXmlDeclarationInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
-    public WriteXmlDeclarationInterceptor() {
-        super(Phase.PRE_STREAM);
-        addBefore(StaxOutInterceptor.class.getName());
-    }
-
-    public void handleMessage(SoapMessage message) throws Fault {
-        message.put("org.apache.cxf.stax.force-start-document", Boolean.TRUE);
-    }
-
-}
-----
-
-As an alternative you can add a message header for it as demonstrated in https://github.com/apache/camel/blob/e818e0103490a106fa1538219f91a732ddebc562/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfConsumerTest.java#L59[CxfConsumerTest]:
-
-[source,java]
--------------------------------------------------------------------
- // set up the response context which force start document
- Map<String, Object> map = new HashMap<String, Object>();
- map.put("org.apache.cxf.stax.force-start-document", Boolean.TRUE);
- exchange.getMessage().setHeader(Client.RESPONSE_CONTEXT, map);
--------------------------------------------------------------------
-
-== How to override the CXF producer address from message header
-
-The `camel-cxf` producer supports to override the target service address by
-setting a message header `CamelDestinationOverrideUrl`.
-
-[source,java]
-----------------------------------------------------------------------------------------------
- // set up the service address from the message header to override the setting of CXF endpoint
- exchange.getIn().setHeader(Exchange.DESTINATION_OVERRIDE_URL, constant(getServiceAddress()));
-----------------------------------------------------------------------------------------------
-
-== How to consume a message from a camel-cxf endpoint in POJO data format
-
-The `camel-cxf` endpoint consumer POJO data format is based on the
-http://cxf.apache.org/docs/invokers.html[CXF invoker], so the
-message header has a property with the name of
-`CxfConstants.OPERATION_NAME` and the message body is a list of the SEI
-method parameters.
-
-Consider the https://github.com/apache/camel/blob/main/components/camel-cxf/src/test/java/org/apache/camel/wsdl_first/PersonProcessor.java[PersonProcessor] example code:
-
-[source,java]
-----
-public class PersonProcessor implements Processor {
-
-    private static final Logger LOG = LoggerFactory.getLogger(PersonProcessor.class);
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public void process(Exchange exchange) throws Exception {
-        LOG.info("processing exchange in camel");
-
-        BindingOperationInfo boi = (BindingOperationInfo) exchange.getProperty(BindingOperationInfo.class.getName());
-        if (boi != null) {
-            LOG.info("boi.isUnwrapped" + boi.isUnwrapped());
-        }
-        // Get the parameters list which element is the holder.
-        MessageContentsList msgList = (MessageContentsList) exchange.getIn().getBody();
-        Holder<String> personId = (Holder<String>) msgList.get(0);
-        Holder<String> ssn = (Holder<String>) msgList.get(1);
-        Holder<String> name = (Holder<String>) msgList.get(2);
-
-        if (personId.value == null || personId.value.length() == 0) {
-            LOG.info("person id 123, so throwing exception");
-            // Try to throw out the soap fault message
-            org.apache.camel.wsdl_first.types.UnknownPersonFault personFault
-                    = new org.apache.camel.wsdl_first.types.UnknownPersonFault();
-            personFault.setPersonId("");
-            org.apache.camel.wsdl_first.UnknownPersonFault fault
-                    = new org.apache.camel.wsdl_first.UnknownPersonFault("Get the null value of person name", personFault);
-            exchange.getMessage().setBody(fault);
-            return;
-        }
-
-        name.value = "Bonjour";
-        ssn.value = "123";
-        LOG.info("setting Bonjour as the response");
-        // Set the response message, first element is the return value of the operation,
-        // the others are the holders of method parameters
-        exchange.getMessage().setBody(new Object[] { null, personId, ssn, name });
-    }
-
-}
-----
-
-== How to prepare the message for the camel-cxf endpoint in POJO data format
-
-The `camel-cxf` endpoint producer is based on the
-https://github.com/apache/cxf/blob/master/core/src/main/java/org/apache/cxf/endpoint/Client.java[CXF
-client API]. First you need to specify the operation name in the message
-header, then add the method parameters to a list, and initialize the
-message with this parameter list. The response message's body is a
-messageContentsList, you can get the result from that list.
-
-If you don't specify the operation name in the message header,
-`CxfProducer` will try to use the `defaultOperationName` from
-`CxfEndpoint`, if there is no `defaultOperationName` set on
-`CxfEndpoint`, it will pick up the first operationName from the Operation
-list.
-
-If you want to get the object array from the message body, you can get
-the body using `message.getBody(Object[].class)`, as shown in https://github.com/apache/camel/blob/e818e0103490a106fa1538219f91a732ddebc562/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfProducerRouterTest.java#L116[CxfProducerRouterTest.testInvokingSimpleServerWithParams]:
-
-[source,java]
-----
-Exchange senderExchange = new DefaultExchange(context, ExchangePattern.InOut);
-final List<String> params = new ArrayList<>();
-// Prepare the request message for the camel-cxf procedure
-params.add(TEST_MESSAGE);
-senderExchange.getIn().setBody(params);
-senderExchange.getIn().setHeader(CxfConstants.OPERATION_NAME, ECHO_OPERATION);
-
-Exchange exchange = template.send("direct:EndpointA", senderExchange);
+Exchange exchange = template.send("direct:EndpointA", senderExchange);
 
 org.apache.camel.Message out = exchange.getMessage();
 // The response message's body is an MessageContentsList which first element is the return value of the operation,
@@ -648,14 +267,14 @@ assertEquals("UTF-8", responseContext.get(org.apache.cxf.message.Message.ENCODIN
 assertEquals("echo " + TEST_MESSAGE, result.get(0), "Reply body on Camel is wrong");
 ----
 
-== How to deal with the message for a camel-cxf endpoint in PAYLOAD data format
+== How to consume a message from a camel-cxf endpoint in PAYLOAD data format
 
 `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
 for SOAP message headers and the SOAP body.
 
-See https://github.com/apache/camel/blob/e818e0103490a106fa1538219f91a732ddebc562/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfConsumerPayloadTest.java#L66[CxfConsumerPayloadTest]:
+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]:
 
 [source,java]
 ----
@@ -736,7 +355,7 @@ InsertResponseOutHeaderProcessor and InsertRequestOutHeaderProcessor are
 actually the same. The only difference between the two processors is
 setting the direction of the inserted SOAP header.
 
-You can find the `InsertResponseOutHeaderProcessor` example in https://github.com/apache/camel/blob/e818e0103490a106fa1538219f91a732ddebc562/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/soap/headers/CxfMessageHeadersRelayTest.java#L730[CxfMessageHeadersRelayTest]:
+You can find the `InsertResponseOutHeaderProcessor` example in https://github.com/apache/camel/blob/main/components/camel-cxf/camel-cxf-spring-soap/src/test/java/org/apache/camel/component/cxf/soap/headers/CxfMessageHeadersRelayTest.java#L731CxfMessageHeadersRelayTest]:
 
 [source,java]
 ----
@@ -765,13 +384,13 @@ public static class InsertResponseOutHeaderProcessor implements Processor {
 == How to get and set SOAP headers in PAYLOAD mode
 
 We've already shown how to access the SOAP message as CxfPayload object in
-PAYLOAD mode inm the section <<How to deal with the message for a camel-cxf endpoint in PAYLOAD data format>>.
+PAYLOAD mode in the section <<How to consume a message from a camel-cxf endpoint in PAYLOAD data format>>.
 
 Once you obtain a CxfPayload object, you can invoke the
 CxfPayload.getHeaders() method that returns a List of DOM Elements (SOAP
 headers).
 
-For an example see https://github.com/apache/camel/blob/e818e0103490a106fa1538219f91a732ddebc562/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfPayLoadSoapHeaderTest.java#L51[CxfPayLoadSoapHeaderTest]:
+For an example see https://github.com/apache/camel/blob/main/components/camel-cxf/camel-cxf-soap/src/test/java/org/apache/camel/component/cxf/jaxws/CxfPayLoadSoapHeaderTest.java#L53[CxfPayLoadSoapHeaderTest]:
 
 [source,java]
 ----
@@ -817,9 +436,9 @@ forwarded to the CXF service. If you do not want that these headers are
 forwarded you have to remove them in the Camel header
 "org.apache.cxf.headers.Header.list".
 
-== SOAP headers are not available in MESSAGE mode
+== SOAP headers are not available in RAW mode
 
-SOAP headers are not available in MESSAGE mode as SOAP processing is
+SOAP headers are not available in RAW mode as SOAP processing is
 skipped.
 
 == How to throw a SOAP Fault from Camel
@@ -827,8 +446,8 @@ skipped.
 If you are using a `camel-cxf` endpoint to consume the SOAP request, you
 may need to throw the SOAP Fault from the camel context. +
  Basically, you can use the `throwFault` DSL to do that; it works for
-`POJO`, `PAYLOAD` and `MESSAGE` data format. +
- You can define the soap fault as shown in https://github.com/apache/camel/blob/e818e0103490a106fa1538219f91a732ddebc562/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfCustomizedExceptionTest.java#L64[CxfCustomizedExceptionTest]:
+`POJO`, `PAYLOAD` and `RAW` data format. +
+ You can define the soap fault as shown in https://github.com/apache/camel/blob/main/components/camel-cxf/camel-cxf-soap/src/test/java/org/apache/camel/component/cxf/jaxws/CxfCustomizedExceptionTest.java#L65[CxfCustomizedExceptionTest]:
 
 [source,java]
 ----
@@ -847,9 +466,9 @@ from(routerEndpointURI).setFaultBody(constant(SOAP_FAULT));
 ----
 
 
-If your CXF endpoint is working in the `MESSAGE` data format, you could
+If your CXF endpoint is working in the `RAW` data format, you could
 set the SOAP Fault message in the message body and set the response
-code in the message header as demonstrated by https://github.com/apache/camel/blob/e818e0103490a106fa1538219f91a732ddebc562/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfMessageStreamExceptionTest.java#L43[CxfMessageStreamExceptionTest]
+code in the message header as demonstrated by https://github.com/apache/camel/blob/main/components/camel-cxf/camel-cxf-soap/src/test/java/org/apache/camel/component/cxf/jaxws/CxfMessageStreamExceptionTest.java#L43[CxfMessageStreamExceptionTest]
 
 [source,java]
 ----
@@ -905,12 +524,10 @@ response context with the following code:
 
 == Attachment Support
 
-*POJO Mode:* Both SOAP with Attachment and MTOM are supported (see
-example in Payload Mode for enabling MTOM).  However, SOAP with
-Attachment is not tested.  Since attachments are marshalled and
-unmarshalled into POJOs, users typically do not need to deal with the
-attachment themself.  Attachments are propagated to Camel message's
-attachments if the MTOM is not enabled.  So, it is
+*POJO Mode:* MTOM are supported if is enabled(see
+example in Payload Mode for enabling MTOM).  Since attachments are 
+marshalled and unmarshalled into POJOs, the attachments should be 
+retrieved from Camel Message Body(As parameter list), and it isn't
 possible to retrieve attachments by Camel Message API
 
 [source,java]
@@ -938,190 +555,535 @@ To enable MTOM, set the CXF endpoint property "mtom-enabled" to _true_.
          <!--  enable mtom by setting this property to true -->
          <entry key="mtom-enabled" value="true"/>
 
-         <!--  set the camel-cxf endpoint data fromat to PAYLOAD mode -->
-         <entry key="dataFormat" value="PAYLOAD"/>
-     </cxf:properties>
-</cxf:cxfEndpoint>
-----
+         <!--  set the camel-cxf endpoint data fromat to PAYLOAD mode -->
+         <entry key="dataFormat" value="PAYLOAD"/>
+     </cxf:properties>
+</cxf:cxfEndpoint>
+----
+
+You can produce a Camel message with attachment to send to a CXF
+endpoint in Payload mode.
+
+[source,java]
+----
+Exchange exchange = context.createProducerTemplate().send("direct:testEndpoint", new Processor() {
+
+    public void process(Exchange exchange) throws Exception {
+        exchange.setPattern(ExchangePattern.InOut);
+        List<Source> elements = new ArrayList<Source>();
+        elements.add(new DOMSource(DOMUtils.readXml(new StringReader(MtomTestHelper.REQ_MESSAGE)).getDocumentElement()));
+        CxfPayload<SoapHeader> body = new CxfPayload<SoapHeader>(new ArrayList<SoapHeader>(),
+            elements, null);
+        exchange.getIn().setBody(body);
+        exchange.getIn(AttachmentMessage.class).addAttachment(MtomTestHelper.REQ_PHOTO_CID,
+            new DataHandler(new ByteArrayDataSource(MtomTestHelper.REQ_PHOTO_DATA, "application/octet-stream")));
+
+        exchange.getIn(AttachmentMessage.class).addAttachment(MtomTestHelper.REQ_IMAGE_CID,
+            new DataHandler(new ByteArrayDataSource(MtomTestHelper.requestJpeg, "image/jpeg")));
+
+    }
+
+});
+
+// process response 
+
+CxfPayload<SoapHeader> out = exchange.getMessage().getBody(CxfPayload.class);
+assertEquals(1, out.getBody().size());
+
+Map<String, String> ns = new HashMap<>();
+ns.put("ns", MtomTestHelper.SERVICE_TYPES_NS);
+ns.put("xop", MtomTestHelper.XOP_NS);
+
+XPathUtils xu = new XPathUtils(ns);
+Element oute = new XmlConverter().toDOMElement(out.getBody().get(0));
+Element ele = (Element) xu.getValue("//ns:DetailResponse/ns:photo/xop:Include", oute,
+                XPathConstants.NODE);
+String photoId = ele.getAttribute("href").substring(4); // skip "cid:"
+
+ele = (Element) xu.getValue("//ns:DetailResponse/ns:image/xop:Include", oute,
+                XPathConstants.NODE);
+String imageId = ele.getAttribute("href").substring(4); // skip "cid:"
+
+DataHandler dr = exchange.getMessage(AttachmentMessage.class).getAttachment(decodingReference(photoId));
+assertEquals("application/octet-stream", dr.getContentType());
+assertArrayEquals(MtomTestHelper.RESP_PHOTO_DATA, IOUtils.readBytesFromStream(dr.getInputStream()));
+
+dr = exchange.getMessage(AttachmentMessage.class).getAttachment(decodingReference(imageId));
+assertEquals("image/jpeg", dr.getContentType());
+
+BufferedImage image = ImageIO.read(dr.getInputStream());
+assertEquals(560, image.getWidth());
+assertEquals(300, image.getHeight());
+----
+
+You can also consume a Camel message received from a CXF endpoint in
+Payload mode.
+The https://github.com/apache/camel/blob/main/components/camel-cxf/camel-cxf-spring-soap/src/test/java/org/apache/camel/component/cxf/mtom/CxfMtomConsumerPayloadModeTest.java#L97[CxfMtomConsumerPayloadModeTest] illustrates how this works:
+
+[source,java]
+----
+public static class MyProcessor implements Processor {
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public void process(Exchange exchange) throws Exception {
+            CxfPayload<SoapHeader> in = exchange.getIn().getBody(CxfPayload.class);
+
+            // verify request
+            assertEquals(1, in.getBody().size());
+
+            Map<String, String> ns = new HashMap<>();
+            ns.put("ns", MtomTestHelper.SERVICE_TYPES_NS);
+            ns.put("xop", MtomTestHelper.XOP_NS);
+
+            XPathUtils xu = new XPathUtils(ns);
+            Element body = new XmlConverter().toDOMElement(in.getBody().get(0));
+            Element ele = (Element) xu.getValue("//ns:Detail/ns:photo/xop:Include", body,
+                    XPathConstants.NODE);
+            String photoId = ele.getAttribute("href").substring(4); // skip "cid:"
+            assertEquals(MtomTestHelper.REQ_PHOTO_CID, photoId);
+
+            ele = (Element) xu.getValue("//ns:Detail/ns:image/xop:Include", body,
+                    XPathConstants.NODE);
+            String imageId = ele.getAttribute("href").substring(4); // skip "cid:"
+            assertEquals(MtomTestHelper.REQ_IMAGE_CID, imageId);
+
+            DataHandler dr = exchange.getIn(AttachmentMessage.class).getAttachment(photoId);
+            assertEquals("application/octet-stream", dr.getContentType());
+            assertArrayEquals(MtomTestHelper.REQ_PHOTO_DATA, IOUtils.readBytesFromStream(dr.getInputStream()));
+
+            dr = exchange.getIn(AttachmentMessage.class).getAttachment(imageId);
+            assertEquals("image/jpeg", dr.getContentType());
+            assertArrayEquals(MtomTestHelper.requestJpeg, IOUtils.readBytesFromStream(dr.getInputStream()));
+
+            // create response
+            List<Source> elements = new ArrayList<>();
+            elements.add(new DOMSource(StaxUtils.read(new StringReader(MtomTestHelper.RESP_MESSAGE)).getDocumentElement()));
+            CxfPayload<SoapHeader> sbody = new CxfPayload<>(
+                    new ArrayList<SoapHeader>(),
+                    elements, null);
+            exchange.getMessage().setBody(sbody);
+            exchange.getMessage(AttachmentMessage.class).addAttachment(MtomTestHelper.RESP_PHOTO_CID,
+                    new DataHandler(new ByteArrayDataSource(MtomTestHelper.RESP_PHOTO_DATA, "application/octet-stream")));
+
+            exchange.getMessage(AttachmentMessage.class).addAttachment(MtomTestHelper.RESP_IMAGE_CID,
+                    new DataHandler(new ByteArrayDataSource(MtomTestHelper.responseJpeg, "image/jpeg")));
+
+        }
+    }
+}
+----
+
+*RAW Mode:* Attachments are not supported as it does not process the
+message at all.
+
+*CXF_MESSAGE Mode*: MTOM is supported, and Attachments can be retrieved
+by Camel Message APIs mentioned above. Note that when receiving a
+multipart (i.e. MTOM) message the default SOAPMessage to String
+converter will provide the complete multipart payload on the body. If
+you require just the SOAP XML as a String, you can set the message body
+with message.getSOAPPart(), and Camel convert can do the rest of work
+for you.
+
+== Streaming Support in PAYLOAD mode
+
+The camel-cxf component now supports streaming of incoming
+messages when using PAYLOAD mode. Previously, the incoming messages
+would have been completely DOM parsed. For large messages, this is time
+consuming and uses a significant amount of memory. The incoming messages can remain as a javax.xml.transform.Source while
+being routed and, if nothing modifies the payload, can then be directly
+streamed out to the target destination. For common "simple proxy" use
+cases (example: from("cxf:...").to("cxf:...")), this can provide very
+significant performance increases as well as significantly lowered
+memory requirements.
+
+However, there are cases where streaming may not be appropriate or
+desired. Due to the streaming nature, invalid incoming XML may not be
+caught until later in the processing chain. Also, certain actions may
+require the message to be DOM parsed anyway (like WS-Security or message
+tracing and such) in which case the advantages of the streaming is
+limited. At this point, there are two ways to control the streaming:
+
+* Endpoint property: you can add "allowStreaming=false" as an endpoint
+property to turn the streaming on/off.
+
+* Component property: the CxfComponent object also has an allowStreaming
+property that can set the default for endpoints created from that
+component.
+
+Global system property: you can add a system property of
+"org.apache.camel.component.cxf.streaming" to "false" to turn it off.
+That sets the global default, but setting the endpoint property above
+will override this value for that endpoint.
+
+== Using the generic CXF Dispatch mode
+
+The camel-cxf component supports the generic
+https://cxf.apache.org/docs/jax-ws-dispatch-api.html[CXF dispatch
+mode] that can transport messages of arbitrary structures (i.e., not
+bound to a specific XML schema). To use this mode, you simply omit
+specifying the wsdlURL and serviceClass attributes of the CXF endpoint.
+
+[source,xml]
+-------------------------------------------------------------------------------------------
+<cxf:cxfEndpoint id="testEndpoint" address="http://localhost:9000/SoapContext/SoapAnyPort">
+     <cxf:properties>
+       <entry key="dataFormat" value="PAYLOAD"/>
+     </cxf:properties>
+   </cxf:cxfEndpoint>
+-------------------------------------------------------------------------------------------
+
+It is noted that the default CXF dispatch client does not send a
+specific SOAPAction header. Therefore, when the target service requires
+a specific SOAPAction value, it is supplied in the Camel header using
+the key SOAPAction (case-insensitive).
+
+[#cxf-loggingout-interceptor-in-message-mode]
+=== How to enable CXF's LoggingOutInterceptor in RAW mode
+
+CXF's `LoggingOutInterceptor` outputs outbound message that goes on the
+wire to logging system (Java Util Logging). Since the
+`LoggingOutInterceptor` is in `PRE_STREAM` phase (but `PRE_STREAM` phase
+is removed in `RAW` mode), you have to configure
+`LoggingOutInterceptor` to be run during the `WRITE` phase. The
+following is an example.
+
+[source,xml]
+-------------------------------------------------------------------------------------------------------
+<bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor">
+    <!--  it really should have been user-prestream but CXF does have such phase! -->
+    <constructor-arg value="target/write"/>
+</bean>
+
+<cxf:cxfEndpoint id="serviceEndpoint" address="http://localhost:${CXFTestSupport.port2}/LoggingInterceptorInMessageModeTest/helloworld"
+    serviceClass="org.apache.camel.component.cxf.HelloService">
+    <cxf:outInterceptors>
+        <ref bean="loggingOutInterceptor"/>
+    </cxf:outInterceptors>
+    <cxf:properties>
+        <entry key="dataFormat" value="RAW"/>
+    </cxf:properties>
+</cxf:cxfEndpoint>
+-------------------------------------------------------------------------------------------------------
+
+=== Description of relayHeaders option
+
+There are _in-band_ and _out-of-band_ on-the-wire headers from the
+perspective of a JAXWS WSDL-first developer.
+
+The _in-band_ headers are headers that are explicitly defined as part of
+the WSDL binding contract for an endpoint such as SOAP headers.
+
+The _out-of-band_ headers are headers that are serialized over the wire,
+but are not explicitly part of the WSDL binding contract.
+
+Headers relaying/filtering is bi-directional.
+
+When a route has a CXF endpoint and the developer needs to have
+on-the-wire headers, such as SOAP headers, be relayed along the route to
+be consumed say by another JAXWS endpoint, then `relayHeaders` should be
+set to `true`, which is the default value.
+
+
+=== Available only in POJO mode
+
+The `relayHeaders=true` expresses an intent to relay the headers. The
+actual decision on whether a given header is relayed is delegated to a
+pluggable instance that implements the `MessageHeadersRelay` interface.
+A concrete implementation of `MessageHeadersRelay` will be consulted to
+decide if a header needs to be relayed or not. There is already an
+implementation of `SoapMessageHeadersRelay` which binds itself to
+well-known SOAP name spaces. Currently only out-of-band headers are
+filtered, and in-band headers will always be relayed when
+`relayHeaders=true`. If there is a header on the wire whose name space
+is unknown to the runtime, then a fall back `DefaultMessageHeadersRelay`
+will be used, which simply allows all headers to be relayed.
+
+The `relayHeaders=false` setting specifies that all headers in-band and
+out-of-band should be dropped.
+
+You can plugin your own `MessageHeadersRelay` implementations overriding
+or adding additional ones to the list of relays. In order to override a
+preloaded relay instance just make sure that your `MessageHeadersRelay`
+implementation services the same name spaces as the one you looking to
+override. Also note, that the overriding relay has to service all of the
+name spaces as the one you looking to override, or else a runtime
+exception on route start up will be thrown as this would introduce an
+ambiguity in name spaces to relay instance mappings.
+
+[source,xml]
+-------------------------------------------------------------------------------------------------------
+<cxf:cxfEndpoint ...>
+   <cxf:properties>
+     <entry key="org.apache.camel.cxf.message.headers.relays">
+       <list>
+         <ref bean="customHeadersRelay"/>
+       </list>
+     </entry>
+   </cxf:properties>
+ </cxf:cxfEndpoint>
+ <bean id="customHeadersRelay" class="org.apache.camel.component.cxf.soap.headers.CustomHeadersRelay"/>
+-------------------------------------------------------------------------------------------------------
+
+Take a look at the tests that show how you'd be able to relay/drop
+headers here:
+
+https://github.com/apache/camel/blob/main/components/camel-cxf/camel-cxf-spring-soap/src/test/java/org/apache/camel/component/cxf/soap/headers/CxfMessageHeadersRelayTest.java[CxfMessageHeadersRelayTest]
+
+* `POJO` and `PAYLOAD` modes are supported. In `POJO` mode, only
+out-of-band message headers are available for filtering as the in-band
+headers have been processed and removed from header list by CXF. The
+in-band headers are incorporated into the `MessageContentList` in POJO
+mode. The `camel-cxf` component does make any attempt to remove the
+in-band headers from the `MessageContentList`. If filtering of in-band
+headers is required, please use `PAYLOAD` mode or plug in a (pretty
+straightforward) CXF interceptor/JAXWS Handler to the CXF endpoint.
+* The Message Header Relay mechanism has been merged into
+`CxfHeaderFilterStrategy`. The `relayHeaders` option, its semantics, and
+default value remain the same, but it is a property of
+`CxfHeaderFilterStrategy`.
+ Here is an example of configuring it.
+
+[source,xml]
+-------------------------------------------------------------------------------------------------------
+<bean id="dropAllMessageHeadersStrategy" class="org.apache.camel.component.cxf.transport.header.CxfHeaderFilterStrategy">
+
+    <!--  Set relayHeaders to false to drop all SOAP headers -->
+    <property name="relayHeaders" value="false"/>
+
+</bean>
+-------------------------------------------------------------------------------------------------------
+
+Then, your endpoint can reference the `CxfHeaderFilterStrategy`.
+
+[source,xml]
+-------------------------------------------------------------------------------------------------------
+<route>
+    <from uri="cxf:bean:routerNoRelayEndpoint?headerFilterStrategy=#dropAllMessageHeadersStrategy"/>
+    <to uri="cxf:bean:serviceNoRelayEndpoint?headerFilterStrategy=#dropAllMessageHeadersStrategy"/>
+</route>
+-------------------------------------------------------------------------------------------------------
+
+* The `MessageHeadersRelay` interface has changed slightly and has been
+renamed to `MessageHeaderFilter`. It is a property of
+`CxfHeaderFilterStrategy`. Here is an example of configuring user
+defined Message Header Filters:
+
+[source,xml]
+-------------------------------------------------------------------------------------------------------
+<bean id="customMessageFilterStrategy" class="org.apache.camel.component.cxf.transport.header.CxfHeaderFilterStrategy">
+    <property name="messageHeaderFilters">
+        <list>
+            <!--  SoapMessageHeaderFilter is the built in filter.  It can be removed by omitting it. -->
+            <bean class="org.apache.camel.component.cxf.common.header.SoapMessageHeaderFilter"/>
+
+            <!--  Add custom filter here -->
+            <bean class="org.apache.camel.component.cxf.soap.headers.CustomHeaderFilter"/>
+        </list>
+    </property>
+</bean>
+-------------------------------------------------------------------------------------------------------
+
+* In addition to `relayHeaders`, the following properties can be
+configured in `CxfHeaderFilterStrategy`.
+
+[width="100%",cols="10%,10%,80%",options="header",]
+|=======================================================================
+|Name |Required |Description
+|`relayHeaders` |No |All message headers will be processed by Message Header Filters
+ _Type_: `boolean`
+ _Default_: `true`
+
+|`relayAllMessageHeaders` | No |All message headers will be propagated (without processing by Message
+Header Filters)
+ _Type_: `boolean`
+ _Default_: `false`
+
+|`allowFilterNamespaceClash` |No |If two filters overlap in activation namespace, the property control how
+it should be handled. If the value is `true`, last one wins. If the
+value is `false`, it will throw an exception
+ _Type_: `boolean`
+ _Default_: `false`
+|=======================================================================
+
+== How to make the camel-cxf component use log4j instead of java.util.logging
+
+CXF's default logger is `java.util.logging`. If you want to change it to
+log4j, proceed as follows. Create a file, in the classpath, named
+`META-INF/cxf/org.apache.cxf.logger`. This file should contain the
+fully-qualified name of the class,
+`org.apache.cxf.common.logging.Log4jLogger`, with no comments, on a
+single line.
+
+== How to let camel-cxf response start with xml processing instruction
+
+If you are using some SOAP client such as PHP, you will get this kind of
+error, because CXF doesn't add the XML processing instruction
+`<?xml version="1.0" encoding="utf-8"?>`:
+
+---------------------------------------------------------------------------------------
+Error:sendSms: SoapFault exception: [Client] looks like we got no XML document in [...]
+---------------------------------------------------------------------------------------
 
-You can produce a Camel message with attachment to send to a CXF
-endpoint in Payload mode.
+To resolve this issue, you just need to tell StaxOutInterceptor to
+write the XML start document for you, as in the https://github.com/apache/camel/blob/main/components/camel-cxf/camel-cxf-soap/src/test/java/org/apache/camel/component/cxf/jaxws/WriteXmlDeclarationInterceptor.java[WriteXmlDeclarationInterceptor] below:
 
 [source,java]
 ----
-Exchange exchange = context.createProducerTemplate().send("direct:testEndpoint", new Processor() {
-
-    public void process(Exchange exchange) throws Exception {
-        exchange.setPattern(ExchangePattern.InOut);
-        List<Source> elements = new ArrayList<Source>();
-        elements.add(new DOMSource(DOMUtils.readXml(new StringReader(MtomTestHelper.REQ_MESSAGE)).getDocumentElement()));
-        CxfPayload<SoapHeader> body = new CxfPayload<SoapHeader>(new ArrayList<SoapHeader>(),
-            elements, null);
-        exchange.getIn().setBody(body);
-        exchange.getIn(AttachmentMessage.class).addAttachment(MtomTestHelper.REQ_PHOTO_CID,
-            new DataHandler(new ByteArrayDataSource(MtomTestHelper.REQ_PHOTO_DATA, "application/octet-stream")));
-
-        exchange.getIn(AttachmentMessage.class).addAttachment(MtomTestHelper.REQ_IMAGE_CID,
-            new DataHandler(new ByteArrayDataSource(MtomTestHelper.requestJpeg, "image/jpeg")));
+public class WriteXmlDeclarationInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
+    public WriteXmlDeclarationInterceptor() {
+        super(Phase.PRE_STREAM);
+        addBefore(StaxOutInterceptor.class.getName());
+    }
 
+    public void handleMessage(SoapMessage message) throws Fault {
+        message.put("org.apache.cxf.stax.force-start-document", Boolean.TRUE);
     }
 
-});
+}
+----
 
-// process response 
+As an alternative you can add a message header for it as demonstrated in https://github.com/apache/camel/blob/main/components/camel-cxf/camel-cxf-soap/src/test/java/org/apache/camel/component/cxf/jaxws/CxfConsumerTest.java#L62[CxfConsumerTest]:
 
-CxfPayload<SoapHeader> out = exchange.getMessage().getBody(CxfPayload.class);
-assertEquals(1, out.getBody().size());
+[source,java]
+-------------------------------------------------------------------
+ // set up the response context which force start document
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put("org.apache.cxf.stax.force-start-document", Boolean.TRUE);
+ exchange.getOut().setHeader(Client.RESPONSE_CONTEXT, map);
+-------------------------------------------------------------------
 
-Map<String, String> ns = new HashMap<>();
-ns.put("ns", MtomTestHelper.SERVICE_TYPES_NS);
-ns.put("xop", MtomTestHelper.XOP_NS);
+== Configure the CXF endpoints with Spring
 
-XPathUtils xu = new XPathUtils(ns);
-Element oute = new XmlConverter().toDOMElement(out.getBody().get(0));
-Element ele = (Element) xu.getValue("//ns:DetailResponse/ns:photo/xop:Include", oute,
-                XPathConstants.NODE);
-String photoId = ele.getAttribute("href").substring(4); // skip "cid:"
+You can configure the CXF endpoint with the Spring configuration file
+shown below, and you can also embed the endpoint into the `camelContext`
+tags. When you are invoking the service endpoint, you can set the
+`operationName` and `operationNamespace` headers to explicitly state
+which operation you are calling.
 
-ele = (Element) xu.getValue("//ns:DetailResponse/ns:image/xop:Include", oute,
-                XPathConstants.NODE);
-String imageId = ele.getAttribute("href").substring(4); // skip "cid:"
+[source,xml]
+----------------------------------------------------------------------------------------------------------------
+<beans xmlns="http://www.springframework.org/schema/beans"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xmlns:cxf="http://camel.apache.org/schema/cxf"
+        xsi:schemaLocation="
+        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+        http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd
+        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
+     <cxf:cxfEndpoint id="routerEndpoint" address="http://localhost:9003/CamelContext/RouterPort"
+            serviceClass="org.apache.hello_world_soap_http.GreeterImpl"/>
+     <cxf:cxfEndpoint id="serviceEndpoint" address="http://localhost:9000/SoapContext/SoapPort"
+            wsdlURL="testutils/hello_world.wsdl"
+            serviceClass="org.apache.hello_world_soap_http.Greeter"
+            endpointName="s:SoapPort"
+            serviceName="s:SOAPService"
+        xmlns:s="http://apache.org/hello_world_soap_http" />
+     <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
+       <route>
+         <from uri="cxf:bean:routerEndpoint" />
+         <to uri="cxf:bean:serviceEndpoint" />
+       </route>
+    </camelContext>
+  </beans>
+----------------------------------------------------------------------------------------------------------------
 
-DataHandler dr = exchange.getMessage(AttachmentMessage.class).getAttachment(decodingReference(photoId));
-assertEquals("application/octet-stream", dr.getContentType());
-assertArrayEquals(MtomTestHelper.RESP_PHOTO_DATA, IOUtils.readBytesFromStream(dr.getInputStream()));
+Be sure to include the JAX-WS `schemaLocation` attribute specified on
+the root beans element. This allows CXF to validate the file and is
+required. Also note the namespace declarations at the end of the
+`<cxf:cxfEndpoint/>` tag. These declarations are required because the combined `\{namespace}localName` syntax is presently not supported for this tag's
+attribute values.
 
-dr = exchange.getMessage(AttachmentMessage.class).getAttachment(decodingReference(imageId));
-assertEquals("image/jpeg", dr.getContentType());
+The `cxf:cxfEndpoint` element supports many additional attributes:
 
-BufferedImage image = ImageIO.read(dr.getInputStream());
-assertEquals(560, image.getWidth());
-assertEquals(300, image.getHeight());
-----
+[width="100%",cols="50%,50%",options="header",]
+|=======================================================================
+|Name |Value
 
-You can also consume a Camel message received from a CXF endpoint in
-Payload mode.
-The https://github.com/apache/camel/blob/e818e0103490a106fa1538219f91a732ddebc562/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/mtom/CxfMtomConsumerPayloadModeTest.java#L98[CxfMtomConsumerPayloadModeTest] illustrates how this works:
+|`PortName` |The endpoint name this service is implementing, it maps to the
+`wsdl:port@name`. In the format of `ns:PORT_NAME` where `ns` is a
+namespace prefix valid at this scope.
 
-[source,java]
-----
-public static class MyProcessor implements Processor {
+|`serviceName` |The service name this service is implementing, it maps to the
+`wsdl:service@name`. In the format of `ns:SERVICE_NAME` where `ns` is a
+namespace prefix valid at this scope.
 
-        @Override
-        @SuppressWarnings("unchecked")
-        public void process(Exchange exchange) throws Exception {
-            CxfPayload<SoapHeader> in = exchange.getIn().getBody(CxfPayload.class);
+|`wsdlURL` |The location of the WSDL. Can be on the classpath, file system, or be
+hosted remotely.
 
-            // verify request
-            assertEquals(1, in.getBody().size());
+|`bindingId` |The `bindingId` for the service model to use.
 
-            Map<String, String> ns = new HashMap<>();
-            ns.put("ns", MtomTestHelper.SERVICE_TYPES_NS);
-            ns.put("xop", MtomTestHelper.XOP_NS);
+|`address` |The service publish address.
 
-            XPathUtils xu = new XPathUtils(ns);
-            Element body = new XmlConverter().toDOMElement(in.getBody().get(0));
-            Element ele = (Element) xu.getValue("//ns:Detail/ns:photo/xop:Include", body,
-                    XPathConstants.NODE);
-            String photoId = ele.getAttribute("href").substring(4); // skip "cid:"
-            assertEquals(MtomTestHelper.REQ_PHOTO_CID, photoId);
+|`bus` |The bus name that will be used in the JAX-WS endpoint.
 
-            ele = (Element) xu.getValue("//ns:Detail/ns:image/xop:Include", body,
-                    XPathConstants.NODE);
-            String imageId = ele.getAttribute("href").substring(4); // skip "cid:"
-            assertEquals(MtomTestHelper.REQ_IMAGE_CID, imageId);
+|`serviceClass` |The class name of the SEI (Service Endpoint Interface) class which could
+have JSR181 annotation or not.
+|=======================================================================
 
-            DataHandler dr = exchange.getIn(AttachmentMessage.class).getAttachment(photoId);
-            assertEquals("application/octet-stream", dr.getContentType());
-            assertArrayEquals(MtomTestHelper.REQ_PHOTO_DATA, IOUtils.readBytesFromStream(dr.getInputStream()));
+It also supports many child elements:
 
-            dr = exchange.getIn(AttachmentMessage.class).getAttachment(imageId);
-            assertEquals("image/jpeg", dr.getContentType());
-            assertArrayEquals(MtomTestHelper.requestJpeg, IOUtils.readBytesFromStream(dr.getInputStream()));
+[width="100%",cols="50%,50%",options="header",]
+|=======================================================================
+|Name |Value
 
-            // create response
-            List<Source> elements = new ArrayList<>();
-            elements.add(new DOMSource(StaxUtils.read(new StringReader(MtomTestHelper.RESP_MESSAGE)).getDocumentElement()));
-            CxfPayload<SoapHeader> sbody = new CxfPayload<>(
-                    new ArrayList<SoapHeader>(),
-                    elements, null);
-            exchange.getMessage().setBody(sbody);
-            exchange.getMessage(AttachmentMessage.class).addAttachment(MtomTestHelper.RESP_PHOTO_CID,
-                    new DataHandler(new ByteArrayDataSource(MtomTestHelper.RESP_PHOTO_DATA, "application/octet-stream")));
+|`cxf:inInterceptors` |The incoming interceptors for this endpoint. A list of `<bean>` or
+`<ref>`.
 
-            exchange.getMessage(AttachmentMessage.class).addAttachment(MtomTestHelper.RESP_IMAGE_CID,
-                    new DataHandler(new ByteArrayDataSource(MtomTestHelper.responseJpeg, "image/jpeg")));
+|`cxf:inFaultInterceptors` |The incoming fault interceptors for this endpoint. A list of `<bean>` or
+`<ref>`.
 
-        }
-    }
-}
-----
+|`cxf:outInterceptors` |The outgoing interceptors for this endpoint. A list of `<bean>` or
+`<ref>`.
 
-*Message Mode:* Attachments are not supported as it does not process the
-message at all.
+|`cxf:outFaultInterceptors` |The outgoing fault interceptors for this endpoint. A list of `<bean>` or
+`<ref>`.
 
-*CXF_MESSAGE Mode*: MTOM is supported, and Attachments can be retrieved
-by Camel Message APIs mentioned above. Note that when receiving a
-multipart (i.e. MTOM) message the default SOAPMessage to String
-converter will provide the complete multipart payload on the body. If
-you require just the SOAP XML as a String, you can set the message body
-with message.getSOAPPart(), and Camel convert can do the rest of work
-for you.
+|`cxf:properties` | A properties map which should be supplied to the JAX-WS endpoint. See
+below.
 
-== Streaming Support in PAYLOAD mode
+|`cxf:handlers` |A JAX-WS handler list which should be supplied to the JAX-WS endpoint.
+See below.
 
-The camel-cxf component now supports streaming of incoming
-messages when using PAYLOAD mode. Previously, the incoming messages
-would have been completely DOM parsed. For large messages, this is time
-consuming and uses a significant amount of memory. The incoming messages can remain as a javax.xml.transform.Source while
-being routed and, if nothing modifies the payload, can then be directly
-streamed out to the target destination. For common "simple proxy" use
-cases (example: from("cxf:...").to("cxf:...")), this can provide very
-significant performance increases as well as significantly lowered
-memory requirements.
+|`cxf:dataBinding` |You can specify the which `DataBinding` will be use in the endpoint.
+This can be supplied using the Spring `<bean class="MyDataBinding"/>`
+syntax.
 
-However, there are cases where streaming may not be appropriate or
-desired. Due to the streaming nature, invalid incoming XML may not be
-caught until later in the processing chain. Also, certain actions may
-require the message to be DOM parsed anyway (like WS-Security or message
-tracing and such) in which case the advantages of the streaming is
-limited. At this point, there are two ways to control the streaming:
+|`cxf:binding` |You can specify the `BindingFactory` for this endpoint to use. This can
+be supplied using the Spring `<bean class="MyBindingFactory"/>` syntax.
 
-* Endpoint property: you can add "allowStreaming=false" as an endpoint
-property to turn the streaming on/off.
+|`cxf:features` |The features that hold the interceptors for this endpoint. A list of
+beans or refs
 
-* Component property: the CxfComponent object also has an allowStreaming
-property that can set the default for endpoints created from that
-component.
+|`cxf:schemaLocations` |The schema locations for endpoint to use. A list of schemaLocations
 
-Global system property: you can add a system property of
-"org.apache.camel.component.cxf.streaming" to "false" to turn it off.
-That sets the global default, but setting the endpoint property above
-will override this value for that endpoint.
+|`cxf:serviceFactory` |The service factory for this endpoint to use. This can be supplied using
+the Spring `<bean class="MyServiceFactory"/>` syntax
+|=======================================================================
 
-== Using the generic CXF Dispatch mode
+You can find more advanced examples that show how to provide
+interceptors, properties and handlers on the CXF
+http://cxf.apache.org/docs/jax-ws-configuration.html[JAX-WS
+Configuration page].
 
-The camel-cxf component supports the generic
-https://cxf.apache.org/docs/jax-ws-dispatch-api.html[CXF dispatch
-mode] that can transport messages of arbitrary structures (i.e., not
-bound to a specific XML schema). To use this mode, you simply omit
-specifying the wsdlURL and serviceClass attributes of the CXF endpoint.
+[NOTE]
+====
+You can use cxf:properties to set the camel-cxf endpoint's dataFormat
+and setDefaultBus properties from spring configuration file.
 
 [source,xml]
--------------------------------------------------------------------------------------------
-<cxf:cxfEndpoint id="testEndpoint" address="http://localhost:9000/SoapContext/SoapAnyPort">
+-------------------------------------------------------------------------
+<cxf:cxfEndpoint id="testEndpoint" address="http://localhost:9000/router"
+     serviceClass="org.apache.camel.component.cxf.HelloService"
+     endpointName="s:PortName"
+     serviceName="s:ServiceName"
+     xmlns:s="http://www.example.com/test">
      <cxf:properties>
-       <entry key="dataFormat" value="PAYLOAD"/>
+       <entry key="dataFormat" value="RAW"/>
+       <entry key="setDefaultBus" value="true"/>
      </cxf:properties>
    </cxf:cxfEndpoint>
--------------------------------------------------------------------------------------------
-
-It is noted that the default CXF dispatch client does not send a
-specific SOAPAction header. Therefore, when the target service requires
-a specific SOAPAction value, it is supplied in the Camel header using
-the key SOAPAction (case-insensitive).
-
- 
+-------------------------------------------------------------------------
+====