cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
Subject [CONF] Apache CXF > Custom CXF Transport
Date Sun, 30 Jan 2011 14:18:00 GMT
    <base href="">
            <link rel="stylesheet" href="/confluence/s/2036/9/15/_/styles/combined.css?spaceKey=CXF&amp;forWysiwyg=true"
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
    <h2><a href="">Custom
CXF Transport</a></h2>
    <h4>Page  <b>added</b> by             <a href="">Andrei
    <div class="notificationGreySide">
         <h1><a name="CustomCXFTransport-ImplementationofCustomCXFTransport"></a>Implementation
of Custom CXF Transport</h1>
<p>This page tries to summarize experience of implementing new CXF transport.</p>

<h2><a name="CustomCXFTransport-UseCases"></a>Use Cases</h2>
<p>Normally implementation of custom transport is required to provide new physical protocol
not yet supported by CXF(for instance udp, ftp). New CXF transport can be also a solution
to support legacy ESB participants that have to be interoperable with JAX-WS services and
Actually CXF 2.3.x distribution provides transport implementation for following protocols:
HTTP(S), JBI, JMS and Local(inside one JVM). Camel additionally implements CXF transport for
camel exchanges.</p>

<h2><a name="CustomCXFTransport-ArchitectureandDesign"></a>Architecture
and Design</h2>
<p>The transport functionality is based on two fundamental definitions: Conduit and
Destination. Conduit is responsible to send a message to recipient and Destination – to
receive a message from the sender. In order to send a response, Destination needs own back-channel
Conduit (in case of request-response communication). Conduit and Destination are created by
TransportFactory. CXF selects a correct TransportFactory based on transport URL. SOAP is also
considered as high level transport and has own Conduit and Destination in CXF.<br/>
To send message into physical channel Conduit should access the message context. Normal practice
in this case is own implementation of OutputStream extending CachedOutputStream. The custom
stream will be set to message and provides a possibility to access context in streaming or
buffered way depending on transport requirements and to send message to physical channel.
CachedOutputStream is configured to keep message in memory only up to limited size. If size
is exceeded, message is swapped to disk.</p>

<p>Class diagram of TransportFactory, Conduit, Destination and OutputStream is shown
<span class="error">&#91;CXF Transport class diagram|^cxf-transport-class-diagram.jpg&#93;</span></p>

<h2><a name="CustomCXFTransport-HowitWorks"></a>How it Works</h2>
<p>Interaction between JAX-WS client and service using CXF transport is represented
on following figure:<br/>
<span class="error">&#91;CXF Transport intercations|^cxf-transport-view.jpg&#93;</span></p>

<h3><a name="CustomCXFTransport-SimplifiedClientWorkflow%3A"></a>Simplified
Client Workflow:</h3>
	<li>Step1: JAX-WS client invokes a service for example in this way:
<div class="code panel" style="border-style: solid;border-width: 1px;"><div class="codeContent
<pre class="code-java">
        URL wsdlURL = <span class="code-keyword">this</span>.getClass().getResource(<span
        HelloWorldService service = <span class="code-keyword">new</span> HelloWorldService(wsdlURL,
        HelloWorld hw = service.getHelloWorldPort();       
        <span class="code-object">String</span> result = hw.sayHi(TEST_REQUEST);
	<li>Step2: CXF runtime select correct TransportFactory based on some criteria (described
	<li>Step3: CXF runtime calls <em>TransportFactory.getConduit()</em> method
to obtain Conduit</li>
	<li>Step4: CXF runtime invokes <em>Conduit.prepare()</em> and passes outgoing
message as argument</li>
	<li>Step5: Conduit sets own OutputStream (normally extended CachedOutputStream) as
outgoing message content</li>
	<li>Step6: CXF runtime processes outgoing message, calls interceptors chain and invokes
Conduit.close(Message) method is invoked for outgoing message.</li>
	<li>Step7: Finally, <em>OutputStream.doClose()</em> method for outgoing
message is invoked</li>
	<li>Step8: In <em>doClose()</em> method OutputStream class has access to
marshalled outgoing message and exchange and will send this message through network to service
using corresponded transport protocol</li>
	<li>Step9: In case of one-way communication exchange will be closed. Go to step 14</li>
	<li>Step10: In case of request-response communication Conduit waits for service response
in synchronies or asynchronies manner</li>
	<li>Step11: When response is received, Conduit creates a new Message, set it’s context
and puts it as In-Message in exchange as incoming message</li>
	<li>Step12: When fault is received, Conduit creates a new Message, sets it’s context
and puts it as fault message in exchange as in-fault message</li>
	<li>Step13: Conduit notifies incomingObesrver about response using <em>incomingObserver.onMessage()</em>
	<li>Step14: <em>Conduit.close(Message)</em> method is invoked for incoming
message. Normally Conduit implementation decreases the reference or closes network connection
with the service.</li>
	<li>Step15: JAX-WS client code receives response in sync or async style</li>

<h3><a name="CustomCXFTransport-SimplifiedServiceWorkflow%3A"></a>Simplified
Service Workflow:</h3>
	<li>Step1: JAX-WS service is registered for example in this way:
<div class="code panel" style="border-style: solid;border-width: 1px;"><div class="codeContent
<pre class="code-java">
	HelloWorldImpl serverImpl = <span class="code-keyword">new</span> HelloWorldImpl();
	Endpoint.publish(<span class="code-quote">"udp:<span class="code-comment">//localhost:9000/hello"</span>,
	<li>Step2: CXF runtime selects correct TransportFactory based on some criteria (described
	<li>Step3: CXF runtime calls <em>TransportFactory.getDestination()</em>
method to obtain Destination</li>
	<li>Step4: As far as service is registered Destination will be activated using <em>Destination.activate()</em>
	<li>Step5: <em>Destination.activate()</em> opens network transport connections
and listen incoming requests</li>
	<li>Step6: When request comes, Destination creates message, sets content and notifies
message observer getMessageObserver.onMessage(). Normally incoming connection is saved in
correlation map to be extracted for appropriate response.</li>
	<li>Step7: Service Implementation will be called with request message. In case of one-way
communication it is end of exchange. In case of request-response business implementation returns
response or throws fault exception.</li>
	<li>Step8: CXF Runtime requests back-channel conduit from destination via <em>Destination.getInbuiltBackChannel()</em></li>
	<li>Step9: Back-channel conduit <em>prepare()</em> will be called with
response message as argument</li>
	<li>Step10: Back-channel conduit sets own OutputStream as message context</li>
	<li>Step11: CXF runtime processes response message, calls interceptors chain and invokes
<em>Conduit.close(Message)</em> method is invoked for response message.</li>
	<li>Step12. Finally <em>OutputStream.doClose()</em> method for response
message is invoked</li>
	<li>Step13: In <em>doClose()</em> method OutputStream class has access
to marshalled response message and exchange and will send this message through the network
as response to. Appropriate incoming connection to send response normally is extracted from
correlation map.</li>

<h2><a name="CustomCXFTransport-RegistrationofTransportFactory"></a>Registration
of Transport Factory</h2>
<p>There are two ways to register transport factory: programmatic and via spring configuration.<br/>
To register transport factory programmatically it is necessary to execute following code:</p>
<div class="code panel" style="border-style: solid;border-width: 1px;"><div class="codeContent
<pre class="code-java">
     Bus bus = BusFactory.getThreadDefaultBus();
     DestinationFactoryManagerImpl dfm = bus.getExtension(DestinationFactoryManagerImpl.class);
     CustomTransportFactory customTransport = <span class="code-keyword">new</span>
     dfm.registerDestinationFactory(<span class="code-quote">"http:<span class="code-comment">//"</span>,
</span>     dfm.registerDestinationFactory(<span class="code-quote">"http:<span
class="code-comment">// TRANSPORT_PREFIX/configuration"</span>,
     ConduitInitiatorManager extension = bus.getExtension(ConduitInitiatorManager.class);
     extension.registerConduitInitiator(<span class="code-quote">"http:<span class="code-comment">//
TRANSPORT_PREFIX"</span>, sbbTransport);
</span>     extension.registerConduitInitiator(<span class="code-quote">"http:<span
class="code-comment">// TRANSPORT_PREFIX/configuration"</span>,
<p>Where TRANSPORT_PREFIX is protocol of new transport (http, https, jms, udp).</p>

<p>Alternatively it is also possible to register transport factory using spring configuration:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
	&lt;bean class=<span class="code-quote">""</span>
		lazy-init=<span class="code-quote">"false"</span>&gt;
		<span class="code-tag">&lt;property name=<span class="code-quote">"transportIds"</span>&gt;</span>
			<span class="code-tag">&lt;list&gt;</span>
			<span class="code-tag">&lt;value&gt;</span>http
TRANSPORT_PREFIX<span class="code-tag">&lt;/value&gt;</span>
                	<span class="code-tag">&lt;value&gt;</span>
TRANSPORT_PREFIX/configuration<span class="code-tag">&lt;/value&gt;</span>
			<span class="code-tag">&lt;/list&gt;</span>
		<span class="code-tag">&lt;/property&gt;</span>
	<span class="code-tag">&lt;/bean&gt;</span>
<p>To define new transport endpoint in WSDL document it is necessary:<br/>
a) Set soap:binding transport attribute to transport URL value (<a href=""
class="external-link" rel="nofollow"></a>)<br/>
b) Port address element should be bound to namespace equals to transport URL in WSDL XML</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
    <span class="code-keyword">xmlns:transport</span>=<span class="code-quote">""</span>
…&gt; …
<span class="code-tag">&lt;wsdl:binding name=<span class="code-quote">"GreeterPortBinding"</span>
type=<span class="code-quote">"tns: GreeterPortType"</span>&gt;</span>
        <span class="code-tag">&lt;soap:binding style=<span class="code-quote">"document"</span>
transport=<span class="code-quote">""</span>/&gt;</span>
<span class="code-tag">&lt;wsdl:service name=<span class="code-quote">"GreeterService"</span>&gt;</span>
       <span class="code-tag">&lt;wsdl:port binding=<span class="code-quote">"tns:GreeterPortBinding"</span>
name=<span class="code-quote">"GreeterPort"</span>&gt;</span>

<h2><a name="CustomCXFTransport-ConduitandDestinationLifecycle"></a>Conduit
and Destination Lifecycle</h2>
<p>Conduit and Destination lifecycle is requested from TransportFactory by every client
or service creation. TransportFactory can either create Conduit and Destination for each request
or cache them based on service endpoint information</p>

<h2><a name="CustomCXFTransport-ConcurrencyAspects"></a>Concurrency Aspects</h2>
<p>Conduit and Destination objects can by concurrently accessed by multiple threads.
Implementations should care about concurrent correlations maps and/or synchronization primitives.</p>

<h2><a name="CustomCXFTransport-References"></a>References</h2>
	<li>CXF transport implementations: package <em>org.apache.cxf.transport.*</em></li>
	<li>CXF Local Transport: <a href=""
class="external-link" rel="nofollow"></a></li>

    <div id="commentsSection" class="wiki-content pageSection">
       <div style="float: right;">
            <a href=""
class="grey">Change Notification Preferences</a>
       <a href="">View
       <a href=";showCommentArea=true#addcomment">Add

View raw message