cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache CXF > Custom CXF Transport
Date Mon, 14 Nov 2011 13:18:00 GMT
<html>
<head>
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/2042/9/15/_/styles/combined.css?spaceKey=CXF&amp;forWysiwyg=true"
type="text/css">
    </head>
<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="https://cwiki.apache.org/confluence/display/CXF/Custom+CXF+Transport">Custom
CXF Transport</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~ashakirin">Andrei
Shakirin</a>
    </h4>
        <br/>
                         <h4>Changes (1)</h4>
                                 
    
<div id="page-diffs">
                    <table class="diff" cellpadding="0" cellspacing="0">
    
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" > <br>     ConduitInitiatorManager
extension = bus.getExtension(ConduitInitiatorManager.class); <br></td></tr>
            <tr><td class="diff-changed-lines" >extension.registerConduitInitiator(&quot;http://cxf.apache.org/transports/TRANSPORT_PREFIX&quot;,
<span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">sbbTransport);</span>
<span class="diff-added-words"style="background-color: #dfd;">customTransport);</span>
<br></td></tr>
            <tr><td class="diff-unchanged" >     extension.registerConduitInitiator(&quot;http://cxf.apache.org/transports/TRANSPORT_PREFIX/configuration&quot;,
customTransport); <br>{code} <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
    
            </table>
    </div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <p>This page summarizes an experience of implementing a new CXF transport.</p>


<h2><a name="CustomCXFTransport-UseCases"></a>Use Cases</h2>
<p>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.</p>

<h2><a name="CustomCXFTransport-ArchitectureandDesign"></a>Architecture
and Design</h2>
<p>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.<br/>
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.</p>

<p>A class diagram of TransportFactory, Conduit, Destination and OutputStream is shown
below:<br/>
<span class="image-wrap" style=""><img src="/confluence/download/attachments/25200212/cxf-transport-class-diagram.jpg?version=2&amp;modificationDate=1296397054000"
style="border: 0px solid black" /></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
in the following figure:<br/>
<span class="image-wrap" style=""><img src="/confluence/download/attachments/25200212/cxf-transport-view.jpg?version=1&amp;modificationDate=1296397054000"
style="border: 0px solid black" /></span></p>

<h3><a name="CustomCXFTransport-SimplifiedClientWorkflow%3A"></a>Simplified
Client Workflow:</h3>
<ul>
	<li>Step1: JAX-WS client invokes a service, in this manner for example:
<div class="code panel" style="border-style: solid;border-width: 1px;"><div class="codeContent
panelContent">
<pre class="code-java">
        URL wsdlURL = <span class="code-keyword">this</span>.getClass().getResource(<span
class="code-quote">"/HelloWorld.wsdl"</span>);
        HelloWorldService service = <span class="code-keyword">new</span> HelloWorldService(wsdlURL,
SERVICE_NAME);        
        HelloWorld hw = service.getHelloWorldPort();       
        <span class="code-object">String</span> result = hw.sayHi(TEST_REQUEST);
}}
</pre>
</div></div></li>
	<li>Step2: CXF runtime selects the correct TransportFactory based on some criteria
(described below)</li>
	<li>Step3: CXF runtime calls <em>TransportFactory.getConduit()</em> method
to obtain the 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 the interceptor chain and
invokes Conduit.close(Message) method for the outgoing message.</li>
	<li>Step7: Finally, <em>OutputStream.doClose()</em> for the outgoing message
is invoked</li>
	<li>Step8: In the <em>doClose()</em> method, the OutputStream class has
access to the marshalled outgoing message and exchange and will send this message to the service
using the corresponding transport protocol</li>
	<li>Step9: In case of one-way communication exchange will be closed. Skip to Step 14</li>
	<li>Step10: In case of request-response communication, the conduit will wait for the
service response in synchronous or asynchronous manner</li>
	<li>Step11: When response is received, the conduit creates a new message, sets its
context and puts it as In-Message in the exchange as an incoming message</li>
	<li>Step12: When fault is received, Conduit creates a new Message, sets its context
and puts it as fault message in exchange as in-fault message</li>
	<li>Step13: Conduit notifies incomingObserver (that is ClientImpl object) about the
response using <em>incomingObserver.onMessage()</em> call</li>
	<li>Step14: <em>Conduit.close(Message)</em> method is invoked for incoming
message. Normally the conduit implementation decreases the reference count with the service,
potentially closing the network connection if the count is zero.</li>
	<li>Step15: JAX-WS client code receives the response in sync or async style</li>
</ul>


<h3><a name="CustomCXFTransport-SimplifiedServiceWorkflow%3A"></a>Simplified
Service Workflow:</h3>
<ul>
	<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
panelContent">
<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>,
serverImpl);</span>
</pre>
</div></div></li>
	<li>Step2: CXF runtime selects correct TransportFactory based on some criteria (described
below)</li>
	<li>Step3: CXF runtime calls <em>TransportFactory.getDestination()</em>
method to obtain the destination</li>
	<li>Step4: As soon as CXF runtime activates endpoint (adds listener, etc) <em>Destination.activate()</em>
method is automatically invoked</li>
	<li>Step5: Implementation of <em>Destination.activate()</em> normally opens
network transport connections and listens to incoming requests</li>
	<li>Step6: When a request comes, the destination creates a message, sets the content
and notifies message observer (that is ChainInitializationObserver object) via <em>incomingObserver.onMessage()</em>
about request. Normally an incoming connection is saved in a correlation map to be extracted
for the appropriate response.</li>
	<li>Step7: The business service implementation will be called with the request message.
In case of one-way communication the exchange is now finished. In case of request-response,
the business implementation either returns a response or throws a fault exception.</li>
	<li>Step8: The CXF Runtime requests a back-channel conduit from the destination via
<em>Destination.getInbuiltBackChannel()</em></li>
	<li>Step9: The Back-channel conduit's <em>prepare()</em> method will be
called with a response message as argument</li>
	<li>Step10: Back-channel conduit sets its own OutputStream as a message context</li>
	<li>Step11: CXF runtime processes the response message, calls the interceptor chain
and invokes <em>Conduit.close(Message)</em> for the response message.</li>
	<li>Step12. Finally <em>OutputStream.doClose()</em> method for the response
message is invoked</li>
	<li>Step13: In <em>doClose()</em> method the OutputStream class has access
to the marshalled response message and will send this message through the network as a response
to the client. Appropriate incoming connection normally is extracted from correlation map.</li>
</ul>


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

<p>For Spring configuration, the following could be used instead:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
	&lt;bean class=<span class="code-quote">"org.company.cxf.transport.CustomTransportFactory"</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 http://cxf.apache.org/transports/TRANSPORT_PREFIX<span
class="code-tag">&lt;/value&gt;</span>
                	<span class="code-tag">&lt;value&gt;</span>http://cxf.apache.org/transports/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>
</pre>
</div></div>
<p>To define a new transport endpoint in the WSDL document follow these two steps:<br/>
a) Set the soap:binding transport attribute to the transport URL value (<a href="http://cxf.apache.org/transports/TRANSPORT_PREFIX"
class="external-link" rel="nofollow">http://cxf.apache.org/transports/TRANSPORT_PREFIX</a>)<br/>
b) The Port address element should be bound to namespace equals to transport URL in WSDL XML</p>

<p>Sample:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
&lt;wsdl:definitions 
    <span class="code-keyword">xmlns:transport</span>=<span class="code-quote">"http://cxf.apache.org/transports/TRANSPORT_PREFIX"</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">"http://cxf.apache.org/transports/TRANSPORT_PREFIX"</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>
           <span class="code-tag">&lt;transport:address location=<span class="code-quote">"LOCATION_URL"</span>&gt;</span>
…
</pre>
</div></div>

<h2><a name="CustomCXFTransport-ConduitandDestinationLifecycle"></a>Conduit
and Destination Lifecycle</h2>
<p>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.</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>
<ol>
	<li>CXF transport implementations: package <em>org.apache.cxf.transport.*</em></li>
	<li>CXF Local Transport: <a href="http://cxf.apache.org/docs/local-transport.html"
class="external-link" rel="nofollow">http://cxf.apache.org/docs/local-transport.html</a></li>
</ol>

    </div>
        <div id="commentsSection" class="wiki-content pageSection">
        <div style="float: right;">
            <a href="https://cwiki.apache.org/confluence/users/viewnotifications.action"
class="grey">Change Notification Preferences</a>
        </div>
        <a href="https://cwiki.apache.org/confluence/display/CXF/Custom+CXF+Transport">View
Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=25200212&revisedVersion=12&originalVersion=11">View
Changes</a>
                |
        <a href="https://cwiki.apache.org/confluence/display/CXF/Custom+CXF+Transport?showComments=true&amp;showCommentArea=true#addcomment">Add
Comment</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message