CXF
Since Camel 1.0
Both producer and consumer are supported
The CXF component provides integration with Apache CXF for connecting to JAX-WS services hosted in CXF.
| When using CXF in streaming mode - check the DataFormat options below, then also read about stream caching. |
Maven users must add the following dependency to their pom.xml for this component:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-cxf-soap</artifactId>
<version>x.x.x</version>
<!-- use the same version as your Camel core version -->
</dependency> URI format
There are two URI formats for this endpoint: cxfEndpoint and someAddress.
cxf:bean:cxfEndpoint[?options]
Where cxfEndpoint represents a bean ID that references a bean in the Spring bean registry. With this URI format, most of the endpoint details are specified in the bean definition.
cxf://someAddress[?options]
Where someAddress specifies the CXF endpoint’s address. With this URI format, most of the endpoint details are specified using options.
For either style above, you can append options to the URI as follows:
cxf:bean:cxfEndpoint?wsdlURL=wsdl/hello_world.wsdl&dataFormat=PAYLOAD
Configuring Options
Camel components are configured on two separate levels:
-
component level
-
endpoint level
Configuring Component Options
At the component level, you set general and shared configurations that are, then, inherited by the endpoints. It is the highest configuration level.
For example, a component may have security settings, credentials for authentication, urls for network connection and so forth.
Some components only have a few options, and others may have many. Because components typically have pre-configured defaults that are commonly used, then you may often only need to configure a few options on a component; or none at all.
You can configure components using:
-
the Component DSL.
-
in a configuration file (
application.properties,*.yamlfiles, etc). -
directly in the Java code.
Configuring Endpoint Options
You usually spend more time setting up endpoints because they have many options. These options help you customize what you want the endpoint to do. The options are also categorized into whether the endpoint is used as a consumer (from), as a producer (to), or both.
Configuring endpoints is most often done directly in the endpoint URI as path and query parameters. You can also use the Endpoint DSL and DataFormat DSL as a type safe way of configuring endpoints and data formats in Java.
A good practice when configuring options is to use Property Placeholders.
Property placeholders provide a few benefits:
-
They help prevent using hardcoded urls, port numbers, sensitive information, and other settings.
-
They allow externalizing the configuration from the code.
-
They help the code to become more flexible and reusable.
The following two sections list all the options, firstly for the component followed by the endpoint.
Component Options
The CXF component supports the following options which are listed below.
| Name | Description | Default | Type |
|---|---|---|---|
Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions (if possible) occurred while the Camel consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. Important: This is only possible if the 3rd party component allows Camel to be alerted if an exception was thrown. Some components handle this internally only, and therefore bridgeErrorHandler is not possible. In other situations we may improve the Camel component to hook into the 3rd party component and make this possible for future releases. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean | |
Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel’s routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing. | false | boolean | |
Whether to always process the exchange synchronously. If true, the producer invokes the CXF Client without a callback and waits until the invocation returns, and the consumer runs the route without a CXF continuation. The component sets the value on each endpoint that it creates, including a bean: endpoint, unless the endpoint URI sets synchronous. | false | boolean | |
Whether to allow CXF to keep the last message part of an incoming SOAP message as a javax.xml.transform.Source read from the stream, instead of parsing it into a DOM. Only used when dataFormat is PAYLOAD. The component sets the value on each endpoint that it creates, including a bean: endpoint, unless the endpoint URI sets allowStreaming. If not set, an endpoint that has no allowStreaming value uses the JVM system property org.apache.camel.component.cxf.streaming, and allows streaming when that property is not set either. | false | Boolean | |
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. | true | boolean | |
To use a custom org.apache.camel.spi.HeaderFilterStrategy to filter header to and from Camel message. | HeaderFilterStrategy | ||
Whether to use the global SSL context parameters of the CamelContext for each endpoint that the component creates and that has no sslContextParameters. The producer uses them for the HTTPS requests that it sends. The consumer does not use them. | false | boolean |
Endpoint Options
The CXF endpoint is configured using URI syntax:
cxf:beanId:address
With the following path and query parameters:
Path Parameters
| Name | Description | Default | Type |
|---|---|---|---|
The id of a CxfEndpoint bean in the registry to use as this endpoint. Written in the path of the endpoint URI in place of the service address, with the prefix bean:, for example bean:orderEndpoint. The component sets the options of the endpoint URI on that bean, so endpoint URIs with different options must not share one bean instance. | String | ||
The service address, for example http://localhost:9000/orders. The consumer receives requests at this address, and the producer sends requests to it. The CamelDestinationOverrideUrl header replaces this address for a request that the producer sends over HTTP. | String |
Query Parameters
| Name | Description | Default | Type |
|---|---|---|---|
How the SOAP message is represented in the Camel message body. POJO: the parameters of the operation as Java objects (requires serviceClass). PAYLOAD: the contents of the soap:Body as a CxfPayload. RAW: the raw message stream from the transport layer, with most CXF interceptors removed, so SOAP headers are not available. CXF_MESSAGE: a SAAJ SOAPMessage, processed by the full set of CXF interceptors. MESSAGE is deprecated and is the same as RAW. Enum values:
| POJO | DataFormat | |
Whether to use the document-literal wrapped style instead of the document-literal bare style for the operations of serviceClass. Not used for RPC-style operations or when serviceClass is a Provider. Otherwise, if not set, CXF uses the parameterStyle of the SOAPBinding annotation, and the wrapped style when there is none. The consumer does not use it when dataFormat is CXF_MESSAGE. | false | Boolean | |
Whether to hide the exception of a failed exchange from the client. If true, the fault that the consumer returns does not contain the class or the message of the exception. This does not apply to a CXF Fault or an exception with the WebFault annotation, nor to a Camel message body that is a Throwable or a CxfPayload with a soap:Fault. | true | boolean | |
Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions (if possible) occurred while the Camel consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. Important: This is only possible if the 3rd party component allows Camel to be alerted if an exception was thrown. Some components handle this internally only, and therefore bridgeErrorHandler is not possible. In other situations we may improve the Camel component to hook into the 3rd party component and make this possible for future releases. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean | |
To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored. | ExceptionHandler | ||
Sets the exchange pattern when the consumer creates an exchange. Enum values:
| ExchangePattern | ||
To use a custom org.apache.camel.http.base.cookie.CookieHandler to keep the cookies of an HTTP session between the requests that the producer sends. An InstanceCookieHandler keeps the cookies in the handler itself, and an ExchangeCookieHandler keeps them in an exchange property. The consumer does not use it. | CookieHandler | ||
The name of the operation that the producer invokes. Used when the Camel message has no CamelCxfOperationName header. If neither the CamelCxfOperationName header nor this option is set, the producer invokes the first operation that CXF returns for the service, in an order that is not defined. If neither wsdlURL nor serviceClass is set, the producer sets this option to Invoke. | String | ||
The namespace of the operation named by the CamelCxfOperationName header or by defaultOperationName. Used when the Camel message has no CamelCxfOperationNamespace header. If neither the CamelCxfOperationNamespace header nor this option is set, the producer uses the namespace of the service, which is the namespace of serviceName when serviceName is set. If neither wsdlURL nor serviceClass is set, the producer sets this option to http://camel.apache.org/cxf/jaxws/dispatch. | String | ||
To use a custom javax.net.ssl.HostnameVerifier for the HTTPS requests that the producer sends. Not used for reading the WSDL that wsdlURL points to. The consumer does not use it. | HostnameVerifier | ||
To use a custom org.apache.camel.support.jsse.SSLContextParameters for the HTTPS requests that the producer sends. If not set, the component sets it to the global SSL context parameters when it creates the endpoint and its own useGlobalSslContextParameters option is true. Not used for reading the WSDL that wsdlURL points to. The consumer does not use it. | SSLContextParameters | ||
Whether to invoke a document-literal wrapped operation in its wrapped form instead of its unwrapped form. If true and dataFormat is POJO, the Camel message body of the request must hold the wrapper object in place of the parameters of the operation. The consumer does not use it. | false | boolean | |
Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel’s routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing. | false | boolean | |
Whether to always process the exchange synchronously. If true, the producer invokes the CXF Client without a callback and waits until the invocation returns, and the consumer runs the route without a CXF continuation. The component sets it to the value of its own synchronous option when it creates the endpoint, including a bean: endpoint, unless the endpoint URI sets it. | false | boolean | |
Whether to allow CXF to keep the last message part of an incoming SOAP message as a javax.xml.transform.Source read from the stream, instead of parsing it into a DOM. Only used when dataFormat is PAYLOAD. The component sets it to the value of its own allowStreaming option when it creates the endpoint, including a bean: endpoint, unless the endpoint URI sets it. If not set, the endpoint uses the JVM system property org.apache.camel.component.cxf.streaming, and allows streaming when that property is not set either. | false | Boolean | |
To use a custom configured CXF Bus. | Bus | ||
The timeout in milliseconds of the CXF continuation that the consumer uses to process the exchange asynchronously. If it expires before the route has completed, the consumer returns a fault to the client and sets an ExchangeTimedOutException on the exchange. Use 0 for no timeout. Not used when synchronous is true or when the consumer gets no continuation from the transport, for example with the JMS transport. | 30000 | long | |
To use a custom CxfBinding to control the binding between Camel Message and CXF Message. | CxfBinding | ||
To use a custom org.apache.camel.component.cxf.jaxws.CxfConfigurer to configure CXF in Java code. Its configure method receives the CXF factory bean before the client or server is created, and configureClient and configureServer receive the created Client or Server. | CxfConfigurer | ||
Whether to set the Bus of this endpoint as the CXF default bus by calling BusFactory.setDefaultBus. This applies to a Bus set with the bus option as well as to a Bus that the endpoint creates. | false | boolean | |
To use a custom HeaderFilterStrategy to filter header to and from Camel message. | HeaderFilterStrategy | ||
Whether to copy a protocol header to the Camel message as one String instead of a List when it has more than one value. The values are joined by a comma and a space. This applies to the request that the consumer receives and to the response that the producer receives. Sets the exchange property CamelCxfProtocolHeadersMerged to true. | false | boolean | |
Whether to send SOAP messages with MTOM, so that CXF writes them as XOP packages. Sets the exchange property mtom-enabled to the value of this option. The producer copies the property to the CXF request message, and the consumer copies it to the CXF response message. When dataFormat is RAW, CXF does not write the Camel message body as an XOP package. | false | boolean | |
To set additional CXF options using the key/value pairs from the Map. For example to turn on stacktraces in SOAP faults, properties.faultStackTraceEnabled=true. This is a multi-value option with prefix: properties. | Map | ||
Whether to validate the incoming and outgoing SOAP messages of the endpoint against the XML schema of the service. Sets the CXF property schema-validation-enabled to the value of this option. If not set, CXF validates only when another setting enables validation, for example the SchemaValidation annotation on serviceClass. When dataFormat is RAW, CXF does not validate the messages. | false | Boolean | |
Whether to skip the check that each element in the SOAP body matches the message part that the operation declares. Sets the CXF property soap.no.validate.parts to true. This is not XML schema validation, which schemaValidationEnabled controls. If dataFormat is PAYLOAD and neither wsdlURL nor serviceClass is set, the producer sets this option to true. | false | boolean | |
Whether to add a LoggingFeature, which writes the incoming and outgoing SOAP messages of the endpoint to the log. The LoggingFeature writes them with SLF4J at INFO level to loggers whose names start with org.apache.cxf.services. | false | boolean | |
The size limit at which CXF truncates a SOAP message in the log. Sets the limit of the LoggingFeature that the endpoint adds when loggingFeatureEnabled is true. Use -1 for no limit. | 49152 | int | |
Whether to skip the log entry that the PhaseInterceptorChain writes when an interceptor throws an exception, for example the exception of a failed exchange of the consumer. Sets the CXF property org.apache.cxf.logging.FaultListener to a FaultListener that skips this log entry. | false | boolean | |
The password for HTTP Basic authentication. The producer puts it, together with the user name, in the protocol header Authorization of its HTTP requests. Only used when the username option is set. Not used for reading the WSDL that wsdlURL points to. The consumer does not use it. | String | ||
The user name for HTTP Basic authentication. The producer puts it, together with the password, in the protocol header Authorization of its HTTP requests. Only used when the password option is set. Not used for reading the WSDL that wsdlURL points to. The consumer does not use it. | String | ||
The id of the CXF binding, which is a namespace URI, for example http://cxf.apache.org/bindings/xformat for the XML binding without a SOAP envelope. If not set, CXF uses the binding of the wsdl:port. The id http://schemas.xmlsoap.org/wsdl/soap12/ selects SOAP 1.2 when there is no WSDL. | String | ||
The WSDL port, which is the name attribute of the wsdl:port element. Written as a QName in the form {namespaceURI}localPart, for example \{http://example.org/orders}OrderPort. | String | ||
The address to publish in the WSDL that the consumer serves at the service address followed by ?wsdl. It replaces the location of the address element in the wsdl:port. Use it when clients reach the service through another address, for example when the service is behind a proxy. | String | ||
The Java class of the service, for example a service endpoint interface or a class that implements one. Written as a fully qualified class name, for example org.example.orders.OrderService. Required when dataFormat is POJO, which is the default. Without a WSDL, CXF builds the service from this class. | Class | ||
The WSDL service, which is the name attribute of the wsdl:service element. Written as a QName in the form {namespaceURI}localPart, for example \{http://example.org/orders}OrderService. If not set and wsdlURL points to a WSDL with one service, that service is used. | String | ||
The location of the WSDL. Can be on the classpath, file system, or be hosted remotely. | String |
Message Headers
The CXF component supports the following message header(s), which is/are listed below:
| Name | Description | Default | Type |
|---|---|---|---|
CamelCxfOperationName (common) Constant: | The name of the operation. | String | |
CamelCxfOperationNamespace (common) Constant: | The namespace of the operation named by the CamelCxfOperationName header or by defaultOperationName. The producer uses it in place of defaultOperationNamespace to find the operation to invoke. The consumer sets it to the namespace of the operation of the request. It is not set when dataFormat is RAW. | String | |
CamelDestinationOverrideUrl (common) Constant: | The address that the producer sends the request to, in place of the service address. With the cxf component, the HTTP transport of CXF uses it, and the Camel transport does not. | String | |
| Constant: | The CXF response context, as a Map. The producer sets it on the Camel message of the response. It holds the CXF properties of the CXF response message, for example the response code. The consumer copies its entries to the CXF response message, but exchange properties and values from the Camel message headers replace entries with the same key. The entry org.apache.cxf.message.Message.PROTOCOL_HEADERS is not used, because the consumer builds the protocol headers from the Camel message headers. | Map | |
| Constant: | The authenticated user of the request, as a Subject. The consumer sets it from the SecurityContext of the CXF request message: the Subject of a LoginSecurityContext, or else a new Subject with the user Principal. | Subject | |
| Constant: | The entries to add to the CXF request context, as a Map. The producer copies them to the CXF request context, but exchange properties and values from the Camel message headers replace entries with the same key. The entry org.apache.cxf.message.Message.PROTOCOL_HEADERS is not used, because the producer builds the protocol headers from the Camel message headers. | Object |
Message Body
The message body at each side of the CXF component: Consumer is the body of the messages the consumer creates, Consumer reply the bodies a consumer that answers its caller can reply with, Producer input the bodies the producer can send or write, and Producer output the body after the producer.
| Side | Body | Description |
|---|---|---|
Consumer |
| 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.
|
Consumer reply |
| POJO: the return value of the operation, of the type the service class declares (a byte array is one value), or a List or an Object 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. RAW: the whole SOAP envelope as text, bytes, a stream or a file. CXF_MESSAGE: a SOAPMessage, a javax.xml.transform Source, or the whole SOAP envelope as text, bytes, a stream or a DOM. A body that does not convert is a SOAP fault.
|
Producer input |
| POJO: the parameters of the operation (the CamelCxfOperationName header or defaultOperationName) as a List (or another Collection) or an Object array, or the one parameter as the body; each of the type the service class declares. Any other body, such as text or a byte array, is the one parameter. 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, a javax.xml.transform Source, or the whole SOAP envelope as text, bytes, a stream or a DOM; another body fails.
|
Producer output |
| 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.
|
The bodies are the ones with the default options. A side that is not listed is not known, and tooling does not guess it. The carriers, the sides and the tools that use them are described in Message Body Types.
The serviceName and portName are QNames, so if you provide them be sure to prefix them with their {namespace} as shown in the examples above.
Descriptions of the data formats
In Apache Camel, the Camel CXF component is the key to integrating routes with Web services. You can use the Camel CXF component to create a CXF endpoint, which can be used in either of the following ways:
-
Consumer — (at the start of a route) represents a Web service instance, which integrates with the route. The type of payload injected into the route depends on the value of the endpoint’s dataFormat option.
-
Producer — (at other points in the route) represents a WS client proxy, which converts the current exchange object into an operation invocation on a remote Web service. The format of the current exchange must match the endpoint’s dataFormat setting.
| DataFormat | Description |
|---|---|
| POJOs (Plain old Java objects) are the Java parameters to the method being invoked on the target server. Both Protocol and Logical JAX-WS handlers are supported. |
|
|
|
|
|
|
You can determine the data format mode of an exchange by retrieving the exchange property, CamelCXFDataFormat. The exchange key constant is defined in org.apache.camel.component.cxf.common.message.CxfConstants.DATA_FORMAT_PROPERTY.
HTTP Transport
When using CXF to host a SOAP-WS then CXF needs to integrate with an HTTP server.
When running in JEE application servers then a Servlet transport can be used. When running in a Java standalone application then CXF has support for using Jetty or Undertow.
-
cxf-rt-transports-http-jetty JAR
-
cxf-rt-transports-http-undertow JAR
Using CXF with Spring Boot or Quarkus comes automatic integrated with the embedded HTTP server.
See more details in the CXF Transport documentation.
Usage
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 SOAPMessag`e 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 the Camel converter can do the rest of the work for you.
The message body that a producer sends, and the reply of a consumer, is a SOAPMessage or a javax.xml.transform.Source of the whole SOAP envelope. Any other body, such as the envelope as a String, byte[], InputStream or DOM Document, is converted to a DOMSource; a body that cannot be converted fails the exchange (a SOAP fault for a consumer).
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 are limited. At this point, there are two ways to control the streaming:
-
Endpoint property: you can add
allowStreaming=falseas an endpoint property to turn the streaming on/off. -
Component property: the
CxfComponentobject also has anallowStreamingproperty 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 CXF dispatch mode that can transport messages of arbitrary structures (i.e., not bound to a specific XML schema). To use this mode, you omit specifying the wsdlURL and serviceClass attributes of the CXF endpoint.
-
Java (Quarkus)
-
XML (Spring)
import org.apache.camel.component.cxf.common.DataFormat;
import org.apache.camel.component.cxf.jaxws.CxfEndpoint;
import jakarta.enterprise.context.SessionScoped;
import jakarta.enterprise.inject.Produces;
import jakarta.inject.Named;
...
@Produces
@SessionScoped
@Named
CxfEndpoint dispatchEndpoint() {
final CxfEndpoint result = new CxfEndpoint();
result.setDataFormat(DataFormat.PAYLOAD);
result.setAddress("/SoapAnyPort");
return result;
} <cxf:cxfEndpoint id="dispatchEndpoint" 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).
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.
LoggingOutInterceptor in the WRITE phase for RAW modeimport java.util.List;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.cxf.common.DataFormat;
import org.apache.camel.component.cxf.jaxws.CxfEndpoint;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.phase.Phase;
import jakarta.enterprise.context.SessionScoped;
import jakarta.enterprise.inject.Produces;
import jakarta.inject.Named;
...
@Produces
@SessionScoped
@Named
CxfEndpoint soapMtomEnabledServerPayloadModeEndpoint() {
final CxfEndpoint result = new CxfEndpoint();
result.setServiceClass(HelloService.class);
result.setDataFormat(DataFormat.RAW);
result.setOutFaultInterceptors(List.of(new LoggingOutInterceptor(Phase.WRITE)));;
result.setAddress("/helloworld");
return result;
} The same configuration in Spring XML:
<bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor">
<!-- it really should have been user-prestream, but CXF does have such a phase! -->
<constructor-arg value="write"/>
</bean>
<cxf:cxfEndpoint id="serviceEndpoint" address="http://localhost:${LoggingInterceptorInMessageModeTest.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 CxfHeaderFilterStrategy options
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, a CxfHeaderFilterStrategy instance should be set on the CXF endpoint, then relayHeaders property of the CxfHeaderFilterStrategy instance should be set to true, which is the default value. Plus, the CxfHeaderFilterStrategy instance also holds a list of MessageHeaderFilter interface, which decides if a specific header will be relayed or not.
Take a look at the tests that show how you’d be able to relay/drop headers here:
-
The
relayHeaders=trueexpresses an intent to relay the headers. The actual decision on whether a given header is relayed is delegated to a pluggable instance that implements theMessageHeaderFilterinterface. A concrete implementation ofMessageHeaderFilterwill be consulted to decide if a header needs to be relayed or not. There is already an implementation ofSoapMessageHeaderFilterwhich binds itself to well-known SOAP name spaces. If there is a header on the wire whose name space is unknown to the runtime, the header will be simply relayed. -
POJOandPAYLOADmodes are supported. InPOJOmode, only out-of-band message headers are available for filtering as the in-band headers have been processed and removed from the header list by CXF. The in-band headers are incorporated into theMessageContentListin POJO mode. The Camel CXF component does make any attempt to remove the in-band headers from theMessageContentList. If filtering of in-band headers is required, please usePAYLOADmode or plug in a (pretty straightforward) CXF interceptor/JAXWS Handler to the CXF endpoint. Here is an example of configuring theCxfHeaderFilterStrategy.
<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:
-
Java
-
XML
-
YAML
from("cxf:bean:routerNoRelayEndpoint?headerFilterStrategy=#dropAllMessageHeadersStrategy")
.to("cxf:bean:serviceNoRelayEndpoint?headerFilterStrategy=#dropAllMessageHeadersStrategy"); <route>
<from uri="cxf:bean:routerNoRelayEndpoint?headerFilterStrategy=#dropAllMessageHeadersStrategy"/>
<to uri="cxf:bean:serviceNoRelayEndpoint?headerFilterStrategy=#dropAllMessageHeadersStrategy"/>
</route> - route:
from:
uri: cxf:bean:routerNoRelayEndpoint
parameters:
headerFilterStrategy: "#dropAllMessageHeadersStrategy"
steps:
- to:
uri: cxf:bean:serviceNoRelayEndpoint
parameters:
headerFilterStrategy: "#dropAllMessageHeadersStrategy" -
You can plug in your own
MessageHeaderFilterimplementations overriding or adding additional ones to the list of relays. To override a preloaded relay instance, make sure that yourMessageHeaderFilterimplementation services the same name spaces as the one you are looking to override.
Here is an example of configuring user defined Message Header Filters:
<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 inCxfHeaderFilterStrategy.
| Name | Required | Description |
|---|---|---|
| No | All message headers will be processed by Message Header Filters Type: |
| No | All message headers will be propagated (without processing by Message Header Filters) Type: |
| No | If two filters overlap in activation namespace, the property controls how it should be handled. If the value is |
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 need to tell StaxOutInterceptor to write the XML start document for you, as in the WriteXmlDeclarationInterceptor below:
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 CxfConsumerTest:
// 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); Configure the CXF endpoints with Spring
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 CamelCxfOperationName and CamelCxfOperationNamespace headers to explicitly state which operation you are calling.
<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> 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.
The cxf:cxfEndpoint element supports many additional attributes:
| Name | Value |
|---|---|
| The endpoint name this service is implementing, it maps to the |
| The service name this service is implementing, it maps to the |
| The location of the WSDL. Can be on the classpath, file system, or be hosted remotely. |
| The |
| The service publish address. |
| The bus name that will be used in the JAX-WS endpoint. |
| The class name of the SEI (Service Endpoint Interface) class which could have JSR181 annotation or not. |
It also supports many child elements:
| Name | Value |
|---|---|
| The incoming interceptors for this endpoint. A list of |
| The incoming fault interceptors for this endpoint. A list of |
| The outgoing interceptors for this endpoint. A list of |
| The outgoing fault interceptors for this endpoint. A list of |
| A properties map which should be supplied to the JAX-WS endpoint. See below. |
| A JAX-WS handler list which should be supplied to the JAX-WS endpoint. See below. |
| You can specify which |
| You can specify the |
| The features that hold the interceptors for this endpoint. A list of beans or refs |
| The schema locations for endpoint to use. A list of schemaLocations |
| The service factory for this endpoint to use. This can be supplied using the Spring |
You can find more advanced examples that show how to provide interceptors, properties and handlers on the CXF JAX-WS Configuration page.
| You can use |
Examples
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 CXF invoker, so the message header has a property with the name of CamelCxfOperationName and the message body is a list of the SEI operation parameters.
Having simple java web service interface:
package org.apache.camel.component.cxf.soap.server;
import jakarta.jws.WebService;
@WebService(targetNamespace = "http://server.soap.cxf.component.camel.apache.org/", name = "TextService", serviceName = "TextService")
public interface TextService {
String upperCase(String text);
String lowerCase(String text);
} We can then create the simplest CXF service (note we didn’t specify the POJO mode, as it is the default mode) as follows:
MessageContentsList processingfrom("cxf:textServiceResponseFromRoute?serviceClass=org.apache.camel.component.cxf.soap.server.TextService&address=/text-route")
.process(exchange -> {
String operation = (String) exchange.getIn().getHeader("CamelCxfOperationName");
String inputArg = ((MessageContentsList) exchange.getIn().getBody()).get(0).toString();
String result = null;
if (operation.equals("upperCase")) {
result = inputArg.toUpperCase();
} else if (operation.equals("lowerCase")) {
result = inputArg.toLowerCase();
}
exchange.getIn().setBody(result);
}); How to prepare the message for the Camel CXF endpoint in POJO data format
The Camel CXF endpoint producer is based on the 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.
A List (or another Collection) or an Object[] body holds the parameters. Any other body, such as a String or a byte[], is the one parameter of the operation: a String with a comma is not split into several parameters.
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 CxfProducerRouterTest.testInvokingSimpleServerWithParams:
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("CamelCxfOperationName", ECHO_OPERATION);
Exchange exchange = template.send("direct:EndpointA", senderExchange);
org.apache.camel.Message out = exchange.getMessage();
// The response message's body is a MessageContentsList which first element is the return value of the operation,
// If there are some holder parameters, the holder parameter will be filled in the reset of List.
// The result will be extracted from the MessageContentsList with the String class type
MessageContentsList result = (MessageContentsList) out.getBody();
LOG.info("Received output text: " + result.get(0));
Map<String, Object> responseContext = CastUtils.cast((Map<?, ?>) out.getHeader(Client.RESPONSE_CONTEXT));
assertNotNull(responseContext);
assertEquals("UTF-8", responseContext.get(org.apache.cxf.message.Message.ENCODING),
"We should get the response context here");
assertEquals("echo " + TEST_MESSAGE, result.get(0), "Reply body on Camel is wrong"); 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.common.CxfPayload object, with getters for SOAP message headers and the SOAP body.
CxfPayload APIfrom(simpleEndpointURI + "&dataFormat=PAYLOAD").to("log:info").process(exchange -> {
CxfPayload<SoapHeader> requestPayload = exchange.getIn().getBody(CxfPayload.class);
List<Source> inElements = requestPayload.getBodySources();
List<Source> outElements = new ArrayList<>();
String request = exchange.getIn().getBody(String.class);
XmlConverter converter = new XmlConverter();
String documentString = ECHO_RESPONSE;
Element in = new XmlConverter().toDOMElement(inElements.get(0));
if (!in.getNamespaceURI().equals(ELEMENT_NAMESPACE)) {
throw new IllegalArgumentException("Wrong element namespace");
}
if (in.getLocalName().equals("echoBoolean")) {
documentString = ECHO_BOOLEAN_RESPONSE;
checkRequest("ECHO_BOOLEAN_REQUEST", request);
} else {
documentString = ECHO_RESPONSE;
checkRequest("ECHO_REQUEST", request);
}
Document outDocument = converter.toDOMDocument(documentString, exchange);
outElements.add(new DOMSource(outDocument.getDocumentElement()));
CxfPayload<SoapHeader> responsePayload = new CxfPayload<>(null, outElements, null);
exchange.getMessage().setBody(responsePayload);
}); How to get and set SOAP headers in POJO mode
POJO means that the data format is a "list of Java objects" when the Camel CXF endpoint produces or consumes Camel exchanges. Even though Camel exposes the message body as POJOs in this mode, Camel CXF still provides access to read and write SOAP headers. However, since CXF interceptors remove in-band SOAP headers from the header list, after they have been processed, only out-of-band SOAP headers are available to Camel CXF in POJO mode.
The following example illustrates how to get/set SOAP headers. Suppose we have a route that forwards from one Camel CXF endpoint to another. That is, SOAP Client → Camel → CXF service. We can attach two processors to obtain/insert SOAP headers at (1) before a request goes out to the CXF service and (2) before the response comes back to the SOAP Client. Processors (1) and (2) in this example are InsertRequestOutHeaderProcessor and InsertResponseOutHeaderProcessor. Our route looks like this:
-
Java
-
XML
-
YAML
from("cxf:bean:routerRelayEndpointWithInsertion")
.process(new InsertRequestOutHeaderProcessor())
.to("cxf:bean:serviceRelayEndpointWithInsertion")
.process(new InsertResponseOutHeaderProcessor()); <route>
<from uri="cxf:bean:routerRelayEndpointWithInsertion"/>
<process ref="InsertRequestOutHeaderProcessor" />
<to uri="cxf:bean:serviceRelayEndpointWithInsertion"/>
<process ref="InsertResponseOutHeaderProcessor" />
</route> - route:
from:
uri: cxf:bean:routerRelayEndpointWithInsertion
steps:
- process:
ref: InsertRequestOutHeaderProcessor
- to:
uri: cxf:bean:serviceRelayEndpointWithInsertion
- process:
ref: InsertResponseOutHeaderProcessor SOAP headers are propagated to and from Camel Message headers. The Camel message header name is org.apache.cxf.headers.Header.list which is a constant defined in CXF (org.apache.cxf.headers.Header.HEADER_LIST). The header value is a List of CXF SoapHeader objects (org.apache.cxf.binding.soap.SoapHeader). The following snippet is the InsertResponseOutHeaderProcessor (that inserts a new SOAP header in the response message). The way to access SOAP headers in both 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 CxfMessageHeadersRelayTest:
public static class InsertResponseOutHeaderProcessor implements Processor {
public void process(Exchange exchange) throws Exception {
List<SoapHeader> soapHeaders = CastUtils.cast((List<?>)exchange.getIn().getHeader(Header.HEADER_LIST));
// Insert a new header
String xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><outofbandHeader "
+ "xmlns=\"http://cxf.apache.org/outofband/Header\" hdrAttribute=\"testHdrAttribute\" "
+ "xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" soap:mustUnderstand=\"1\">"
+ "<name>New_testOobHeader</name><value>New_testOobHeaderValue</value></outofbandHeader>";
SoapHeader newHeader = new SoapHeader(soapHeaders.get(0).getName(),
DOMUtils.readXml(new StringReader(xml)).getDocumentElement());
// make sure the direction is OUT since it is a response message.
newHeader.setDirection(Direction.DIRECTION_OUT);
//newHeader.setMustUnderstand(false);
soapHeaders.add(newHeader);
}
} 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 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 example, see CxfPayLoadSoapHeaderTest:
CxfPayload in PAYLOAD modefrom(getRouterEndpointURI()).process(exchange -> {
CxfPayload<SoapHeader> payload = exchange.getIn().getBody(CxfPayload.class);
List<Source> elements = payload.getBodySources();
assertNotNull(elements, "We should get the elements here");
assertEquals(1, elements.size(), "Get the wrong elements size");
Element el = new XmlConverter().toDOMElement(elements.get(0));
elements.set(0, new DOMSource(el));
assertEquals("http://camel.apache.org/pizza/types",
el.getNamespaceURI(), "Get the wrong namespace URI");
List<SoapHeader> headers = payload.getHeaders();
assertNotNull(headers, "We should get the headers here");
assertEquals(1, headers.size(), "Get the wrong headers size");
assertEquals("http://camel.apache.org/pizza/types",
((Element) (headers.get(0).getObject())).getNamespaceURI(), "Get the wrong namespace URI");
headers = exchange.getIn().getHeader(Header.HEADER_LIST, List.class);
assertNotNull(headers, "We should get the headers here");
assertEquals(1, headers.size(), "Get the wrong headers size");
assertEquals("http://camel.apache.org/pizza/types",
((Element) (headers.get(0).getObject())).getNamespaceURI(), "Get the wrong namespace URI");
})
.to(getServiceEndpointURI()); You can also use the same way as described in subchapter "How to get and set SOAP headers in POJO mode" to set or get the SOAP headers. So, you can use the header org.apache.cxf.headers.Header.list to get and set a list of SOAP headers.This does also mean that if you have a route that forwards from one Camel CXF endpoint to another (SOAP Client → Camel → CXF service), now also the SOAP headers sent by the SOAP client are 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 RAW mode
SOAP headers are not available in RAW mode as SOAP processing is skipped.
How to throw a SOAP Fault from Camel
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 set the SoapFault as the message body to do that; it works for POJO, PAYLOAD and RAW data format.
You can define the soap fault as shown in CxfCustomizedExceptionTest:
SoapFault with detail textSOAP_FAULT = new SoapFault(EXCEPTION_MESSAGE, SoapFault.FAULT_CODE_CLIENT);
Element detail = SOAP_FAULT.getOrCreateDetail();
Document doc = detail.getOwnerDocument();
Text tn = doc.createTextNode(DETAIL_TEXT);
detail.appendChild(tn); Then throw it as you like:
from(routerEndpointURI).process(exchange -> exchange.getMessage().setBody(SOAP_FAULT)); 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 CxfMessageStreamExceptionTest:
from(routerEndpointURI)
.process(exchange -> {
Message out = exchange.getMessage();
out.setBody(this.getClass().getResourceAsStream("SoapFaultMessage.xml"));
out.setHeader(org.apache.cxf.message.Message.RESPONSE_CODE, 500);
}); Same for using POJO data format. You can set the SOAPFault on the OUT body.
How to propagate a Camel CXF endpoint’s request and response context
CXF client API provides a way to invoke the operation with request and response context. If you are using a Camel CXF endpoint producer to invoke the outside web service, you can set the request context and get response context with the following code:
CxfExchange exchange = (CxfExchange)template.send(getJaxwsEndpointUri(), ex -> {
final List<String> params = new ArrayList<String>();
params.add(TEST_MESSAGE);
Map<String, Object> requestContext = new HashMap<String, Object>();
requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, JAXWS_SERVER_ADDRESS);
ex.getIn().setBody(params);
ex.getIn().setHeader(Client.REQUEST_CONTEXT, requestContext);
ex.getIn().setHeader("CamelCxfOperationName", GREET_ME_OPERATION);
});
org.apache.camel.Message out = exchange.getMessage();
// The output is an object array, the first element of the array is the return value
Object\[\] output = out.getBody(Object\[\].class);
LOG.info("Received output text: " + output\[0\]);
// Get the response context form outMessage
Map<String, Object> responseContext = CastUtils.cast((Map)out.getHeader(Client.RESPONSE_CONTEXT));
assertNotNull(responseContext);
assertEquals("Get the wrong wsdl operation name", "{http://apache.org/hello_world_soap_http}greetMe",
responseContext.get("javax.xml.ws.wsdl.operation").toString()); POJO Mode
Message Transmission Optimization Mechanism (MTOM) is supported if enabled - check the example in Payload Mode for enabling MTOM. Since attachments are marshalled and unmarshalled into POJOs, the attachments should be retrieved from the Apache Camel message body (as a parameter list), and it isn’t possible to retrieve attachments by Camel Message API
DataHandler handler = Exchange.getIn(AttachmentMessage.class).getAttachment("id"); Payload Mode
Message Transmission Optimization Mechanism (MTOM) is supported by this Mode. Attachments can be retrieved by Camel Message APIs mentioned above. SOAP with Attachment (SwA) is supported and attachments can be retrieved. SwA is the default (same as setting the CXF endpoint property mtomEnabled to false).
To enable MTOM, set the CXF endpoint property mtomEnabled to true.
You can produce a Camel message with attachment to send to a CXF endpoint in Payload mode.
Exchange exchange = context.createProducerTemplate().send("direct:testEndpoint", ex -> {
ex.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);
ex.getIn().setBody(body);
ex.getIn(AttachmentMessage.class).addAttachment(MtomTestHelper.REQ_PHOTO_CID,
new DataHandler(new ByteArrayDataSource(MtomTestHelper.REQ_PHOTO_DATA, "application/octet-stream")));
ex.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 CxfMtomConsumerPayloadModeTest illustrates how this works:
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")));
}
} How can I get the remote connection IP address from the camel-cxf consumer ?
You can access the CXF Message by using the key of CamelCxfMessage from message header, and you can get the ServletRequest instance from the CXF message, then you can get the remote connection IP easily.
Here is the code snippet:
org.apache.cxf.message.Message cxfMessage = exchange.getIn().getHeader(
"CamelCxfMessage", org.apache.cxf.message.Message.class);
ServletRequest request = (ServletRequest) cxfMessage.get("HTTP.REQUEST");
String remoteAddress = request.getRemoteAddr(); How to switch the CXF consumer between HTTP and HTTPS without touching the Spring configuration?
You can find general information how to secure your Camel CXF Consumer with HTTPS in the Apache CXF Client HTTP transport documentation.
A simple Camel CXF Consumer configuration which use the \http:conduit configuration to enable SSL and an external properties file for all environment specific configurations could look like in Spring XML:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ctx="http://www.springframework.org/schema/context"
xmlns:camel="http://camel.apache.org/schema/spring"
xmlns:camel-cxf="http://camel.apache.org/schema/cxf"
xmlns:http="http://cxf.apache.org/transports/http/configuration"
xmlns:sec="http://cxf.apache.org/configuration/security"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
http://camel.apache.org/schema/osgi http://camel.apache.org/schema/osgi/camel-osgi.xsd
http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd
http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd
">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-http-jetty.xml" />
<ctx:property-placeholder location="classpath:orderEntry.cfg" />
<camel-cxf:cxfEndpoint id="orderEntryEndpoint"
address="${endpointUri}"
serviceClass="com.company.product.OrderEntryService"
endpointName="ssp:OrderEntry"
serviceName="ssp:OrderEntryService"
wsdlURL="META-INF/orderEntry/orderEntry.wsdl"
xmlns:ssp="http://www.company.com/product/orderEntry/service/1" />
<http:conduit name="{http://www.company.com/product/orderEntry/service/1}OrderEntry.http-conduit">
<http:tlsClientParameters disableCNCheck="true">
<sec:trustManagers>
<sec:keyStore type="JKS" password="${trustStore.password}" file="${trustStore.file}"/>
</sec:trustManagers>
<sec:cipherSuitesFilter>
<sec:include>.*_EXPORT_.*</sec:include>
<sec:include>.*_EXPORT1024_.*</sec:include>
<sec:include>.*_WITH_DES_.*</sec:include>
<sec:include>.*_WITH_NULL_.*</sec:include>
<sec:exclude>.*_DH_anon_.*</sec:exclude>
</sec:cipherSuitesFilter>
</http:tlsClientParameters>
</http:conduit>
<camel:camelContext trace="true">
<camel:routeBuilder ref="orderEntryRoute" />
</camel:camelContext>
<bean id="orderEntryRoute" class="com.company.product.OrderEntryRoute" />
</beans> The environment specific configurations are externalized into a properties file:
orderEntry.cfg
endpointUri=https://localhost:8181/OrderEntry
trustStore.password=password
trustStore.file=etc/myApp.ts With this configuration, you Camel CXF consumer connects with HTTPS to the web service provider.
If you need to change the protocol to HTTP, maybe for tracing/debugging reasons, change the endpointUri property in your properties file to e.g. http://localhost:8080/OrderEntry.
Apache CXF detects that you only use HTTP and instantiates a HttpURLConnectionFactoryImpl instead of a HttpsURLConnectionFactory.