This page summarizes an experience of implementing a new CXF transport.

Use Cases

Normally implementing a custom transport is required when providing a new physical protocol not yet supported by CXF (udp or ftp, for example). New CXF transports can be also a solution to support legacy ESB participants that have to be interoperable with JAX-WS services and clients. Presently the CXF 2.3.x distribution provides a transport implementation for the following protocols: HTTP(S), JBI, JMS and Local(inside one JVM). Camel additionally implements CXF transport for Camel exchanges.

Architecture and Design

The transport functionality is based on two fundamental definitions: conduit and destination. Conduits are responsible for sending a message to recipients and destinations for receiving a message from the sender. In order to send a response, a destination needs its own back-channel conduit (in case of request-response communication). Conduits and destinations are created by a TransportFactory. CXF selects the correct TransportFactory based on the transport URL. SOAP is also considered a high level transport and has its own conduit and destination in CXF.
To send a message into a physical channel, the conduit should access the message context. Normal practice in this case is to use a subclass of OutputStream extending CachedOutputStream. The custom stream will be fed the message and provides a possibility to access context in streaming or buffered form depending on the transport requirements. CachedOutputStream is configured to keep message in memory only up to a predefined size. If this size is exceeded, the message is swapped to disk.

A class diagram of TransportFactory, Conduit, Destination and OutputStream is shown below:

How it Works

Interaction between JAX-WS client and service using CXF transport is represented in the following figure:

Simplified Client Workflow:

Simplified Service Workflow:

Registration of Transport Factory

There are two ways to register transport factory: programmatically or via Spring configuration.
To register transport factory programmatically it is necessary to execute the following code:

     Bus bus = BusFactory.getThreadDefaultBus();
     DestinationFactoryManagerImpl dfm = bus.getExtension(DestinationFactoryManagerImpl.class);
     CustomTransportFactory customTransport = new CustomTransportFactory();
     dfm.registerDestinationFactory("http://cxf.apache.org/transports/TRANSPORT_PREFIX", customTransport);
     dfm.registerDestinationFactory("http://cxf.apache.org/transports/TRANSPORT_PREFIX/configuration", customTransport);

     ConduitInitiatorManager extension = bus.getExtension(ConduitInitiatorManager.class);
     extension.registerConduitInitiator("http://cxf.apache.org/transports/TRANSPORT_PREFIX", customTransport);
     extension.registerConduitInitiator("http://cxf.apache.org/transports/TRANSPORT_PREFIX/configuration", customTransport);

Where TRANSPORT_PREFIX is the protocol of the new transport (http, https, jms, udp).

For Spring configuration, the following could be used instead:

	<bean class="org.company.cxf.transport.CustomTransportFactory"
		lazy-init="false">
		<property name="transportIds">
			<list>
			<value>http http://cxf.apache.org/transports/TRANSPORT_PREFIX</value>
                	<value>http://cxf.apache.org/transports/TRANSPORT_PREFIX/configuration</value>
			</list>
		</property>
	</bean>

To define a new transport endpoint in the WSDL document follow these two steps:
a) Set the soap:binding transport attribute to the transport URL value (http://cxf.apache.org/transports/TRANSPORT_PREFIX)
b) The Port address element should be bound to namespace equals to transport URL in WSDL XML

Sample:

<wsdl:definitions 
    xmlns:transport="http://cxf.apache.org/transports/TRANSPORT_PREFIX" …> …
…
<wsdl:binding name="GreeterPortBinding" type="tns: GreeterPortType">
        <soap:binding style="document" transport="http://cxf.apache.org/transports/TRANSPORT_PREFIX"/>
…
<wsdl:service name="GreeterService">
       <wsdl:port binding="tns:GreeterPortBinding" name="GreeterPort">
           <transport:address location="LOCATION_URL">
…

Conduit and Destination Lifecycle

The conduit and destination lifecycle can be started by the TransportFactory during every client or service creation. The TransportFactory can either create a conduit and destination for each request or cache them based on service endpoint information.

Concurrency Aspects

Conduit and destination objects can by concurrently accessed by multiple threads. Implementations should care about concurrent correlations maps and/or synchronization primitives.

References

  1. CXF transport implementations: package org.apache.cxf.transport.*
  2. CXF Local Transport: http://cxf.apache.org/docs/local-transport.html