Requirements and Solutions
Sometimes using of native asynchronous transports like JMS is not possible because of technical or political reasons, but asynchronous communication is required anyway.
CXF does have a facilities to help with these types of requirements:
- Using WS-Addressing decoupled response
- Using independent oneway operations
WS-Addressing decoupled response
Decoupled response uses different HTTP channel to send the response. Client in this case acts as a service as well: it opens independent HTTP connection and can receives the messages. The communication is shown on the following picture (used from FuseSource resource)
- The consumer implementation invokes an operation and a request message is generated.
- The WS-Addressing layer adds the WS-A headers to the message. When a decoupled endpoint is specified in the consumer's configuration, the address of the decoupled endpoint is placed in the WS-A ReplyTo header.
- The message is sent to the service provider.
- The service provider receives the message.
- The request message from the consumer is dispatched to the provider's WS-A layer.
- Because the WS-A ReplyTo header is not set to anonymous, the provider sends back a message with the HTTP status code set to 202, acknowledging that the request has been received.
- The HTTP layer sends a 202 Accepted message back to the consumer using the original connection's back-channel. The consumer receives the 202 Accepted reply on the back-channel of the HTTP connection used to send the original message.
- When the consumer receives the 202 Accepted reply, the HTTP connection closes.
- The request is passed to the service provider's implementation where the request is processed.
- When the response is ready, it is dispatched to the WS-A layer.
- The WS-A layer adds the WS-Addressing headers to the response message.
- The HTTP transport sends the response to the consumer's decoupled endpoint.
- The consumer's decoupled endpoint receives the response from the service provider.
- The response is dispatched to the consumer's WS-A layer where it is correlated to the proper request using the WS-A RelatesTo header.
- The correlated response is returned to the client implementation and the invoking call is unblocked.
Configuring decoupled response is trivial: it is necessary to activate WS-Addressing Feature on client and service and provide ReplyTo and FaultTo addresses on the client:
Activation of WS-Addressing Feature
Configuring WSA Properties
Client should configure ReplyTo WS-Addressing property to receive decoupled response:
Alternatively, client can use CXF AddressingPropertiesImpl object to control many aspects of WS-Addressing including ReplyTo:
AddressingProperties maps =
EndpointReferenceType ref =
AttributedURIType add =
Under the HoodCXF makes the following steps on the service side by receiving the client request:
- Creates empty response message (partial response)
- Initializes new interceptor chain: adds all registered interceptors for endpoint, service, bus and binding
- Replaces interceptor chain to the new one
- Creates and replaces ConduitSelector in exchange to PreexistingConduitSelector with original back channel
- Invokes chain.doIntercept() and sends empty response (HTTP status 202)
- Resets the interceptors chain
- Creates and initializes new message for real response
- Creates decoupled destination for the client
- Suspends current interceptor chain for full response and resumes that in new thread
- Service handler will be called from ServiceInvokerInterceptor in new thread and response will be delivered to decoupled destination
I have created two samples illustrating decoupled responses on Git Hub respository:
- Simple scenario based on Java First client and service
- Dispatching scenario based on Provider<T> service and Dispatch client containing code to dispatch responses to registered callbacks
Independent Oneway Operations
WS-Addressing decoupled response is very useful for most of cases, but sometimes you need more flexibility. For example I have seen the requirements to support more than one response to single client request (multi-response conversation) or to persist service state during request processing. In this case you can consider to use two independent oneway operations: one on the service side and second on the client side:
The client registers own endpoint and uses it to receive responses from the service. This solution is very flexible, you can fulfill requirements like:
- receive some responses for the same request;
- dispatch responses to different handlers on the client side;
- persist service state after receiving request, shutdown the service, start up it again when response is ready and send response to client endpoint.