blob: 9a969e2bca3d2d6a7795ecdd2a3ae78f6dbf8dbe [file] [log] [blame]
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html>
<head>
<link type="text/css" rel="stylesheet" href="/resources/site.css">
<script src='/resources/space.js'></script>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<meta name="keywords" content="business integration, EAI, SOA, Service Oriented Architecture, web services, SOAP, JBI, JMS, WSDL, XML, EDI, Electronic Data Interchange, standards support, integration standards, application integration, middleware, software, solutions, services, CXF, open source">
<meta name="description" content="Apache CXF, Services Framework - Custom Transport">
<link type="text/css" rel="stylesheet" href="/resources/highlighter/styles/shCoreCXF.css">
<link type="text/css" rel="stylesheet" href="/resources/highlighter/styles/shThemeCXF.css">
<script src='/resources/highlighter/scripts/shCore.js'></script>
<script src='/resources/highlighter/scripts/shBrushBash.js'></script>
<script src='/resources/highlighter/scripts/shBrushXml.js'></script>
<script src='/resources/highlighter/scripts/shBrushJava.js'></script>
<script>
SyntaxHighlighter.defaults['toolbar'] = false;
SyntaxHighlighter.all();
</script>
<title>
Apache CXF -- Custom Transport
</title>
</head>
<body onload="init()">
<table width="100%" cellpadding="0" cellspacing="0">
<tr>
<td id="cell-0-0" colspan="2">&nbsp;</td>
<td id="cell-0-1">&nbsp;</td>
<td id="cell-0-2" colspan="2">&nbsp;</td>
</tr>
<tr>
<td id="cell-1-0">&nbsp;</td>
<td id="cell-1-1">&nbsp;</td>
<td id="cell-1-2">
<!-- Banner -->
<div class="banner" id="banner"><div><table border="0" cellpadding="0" cellspacing="0" width="100%"><tr><td align="left" colspan="1" nowrap>
<a shape="rect" href="http://cxf.apache.org/" title="Apache CXF"><span style="font-weight: bold; font-size: 170%; color: white">Apache CXF</span></a>
</td><td align="right" colspan="1" nowrap>
<a shape="rect" href="http://www.apache.org/" title="The Apache Sofware Foundation"><img border="0" alt="ASF Logo" src="http://cxf.apache.org/images/asf-logo.png"></a>
</td></tr></table></div></div>
<!-- Banner -->
<div id="top-menu">
<table border="0" cellpadding="1" cellspacing="0" width="100%">
<tr>
<td>
<div align="left">
<!-- Breadcrumbs -->
<a href="index.html">Index</a>&nbsp;&gt;&nbsp;<a href="transports.html">Transports</a>&nbsp;&gt;&nbsp;<a href="custom-transport.html">Custom Transport</a>
<!-- Breadcrumbs -->
</div>
</td>
<td>
<div align="right">
<!-- Quicklinks -->
<div id="quicklinks"><p><a shape="rect" href="http://cxf.apache.org/download.html">Download</a> | <a shape="rect" href="http://cxf.apache.org/docs/index.html">Documentation</a></p></div>
<!-- Quicklinks -->
</div>
</td>
</tr>
</table>
</div>
</td>
<td id="cell-1-3">&nbsp;</td>
<td id="cell-1-4">&nbsp;</td>
</tr>
<tr>
<td id="cell-2-0" colspan="2">&nbsp;</td>
<td id="cell-2-1">
<table>
<tr valign="top">
<td height="100%">
<div id="wrapper-menu-page-right">
<div id="wrapper-menu-page-top">
<div id="wrapper-menu-page-bottom">
<div id="menu-page">
<!-- NavigationBar -->
<div id="navigation"><ul class="alternate"><li><a shape="rect" href="overview.html">Overview</a></li><li><a shape="rect" href="how-tos.html">How-Tos</a></li><li><a shape="rect" href="frontends.html">Frontends</a></li><li><a shape="rect" href="databindings.html">DataBindings</a></li><li><a shape="rect" href="transports.html">Transports</a></li><li><a shape="rect" href="configuration.html">Configuration</a></li><li><a shape="rect" href="debugging-and-logging.html">Debugging and Logging</a></li><li><a shape="rect" href="tools.html">Tools</a></li><li><a shape="rect" href="restful-services.html">RESTful Services</a></li><li><a shape="rect" href="wsdl-bindings.html">WSDL Bindings</a></li><li><a shape="rect" href="service-routing.html">Service Routing</a></li><li><a shape="rect" href="dynamic-languages.html">Dynamic Languages</a></li><li><a shape="rect" href="ws-support.html">WS-* Support</a></li><li><a shape="rect" href="advanced-integration.html">Advanced Integration</a></li><li><a shape="rect" href="deployment.html">Deployment</a></li><li><a shape="rect" href="schemas-and-namespaces.html">Use of Schemas and Namespaces</a></li></ul><hr><ul class="alternate"><li><p>Search</p></li></ul><form enctype="application/x-www-form-urlencoded" method="get" id="cse-search-box" action="http://www.google.com/cse">
<div>
<input type="hidden" name="cx" value="002890367768291051730:o99qiwa09y4">
<input type="hidden" name="ie" value="UTF-8">
<input type="text" name="q" size="21">
<input type="submit" name="sa" value="Search">
</div>
</form>
<script type="text/javascript" src="http://www.google.com/cse/brand?form=cse-search-box&amp;lang=en"></script><hr><ul class="alternate"><li><a shape="rect" href="http://cxf.apache.org/javadoc/latest/">API 3.2.x (Javadoc)</a></li><li><a shape="rect" href="http://cxf.apache.org/javadoc/latest-3.1.x/">API 3.1.x (Javadoc)</a></li><li><a shape="rect" href="http://cxf.apache.org/">CXF Website</a></li></ul><p>&#160;</p><p><a shape="rect" class="external-link" href="http://www.apache.org/events/current-event.html"><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-external-resource" src="http://www.apache.org/events/current-event-125x125.png" data-image-src="http://www.apache.org/events/current-event-125x125.png"></span></a></p></div>
<!-- NavigationBar -->
</div>
</div>
</div>
</div>
</td>
<td height="100%">
<!-- Content -->
<div class="wiki-content">
<div id="ConfluenceContent"><p>This page summarizes an experience and use cases of implementing a new custom CXF transport.</p>
<h2 id="CustomTransport-UseCases">Use Cases</h2>
<p>Basically there are two main use cases for implementing a new CXF transport:</p>
<ol><li>Providing a new physical protocol not yet supported by CXF (udp or ftp, for example). Some such cases can be solved by using integration with a corresponding Camel component, but if no such component is available or workable creating a new custom CXF transport should be considered.</li><li>Supporting tight integration with another framework (like JBI or Camel). In this case integration would be kept transparent for CXF applications - they would just speak directly with the target framework on the transport level. Here, the Transport implementation would be responsible for converting and transferring CXF exchange, messages and faults to target framework.</li></ol>
<p>Presently the CXF distribution provides a transport implementation for the following protocols: HTTP(S), JBI, JMS and Local(inside one JVM). Camel additionally implements a CXF transport for Camel exchanges.</p>
<h2 id="CustomTransport-ArchitectureandDesign">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 clear="none">
To send a message into a physical channel, the conduit should access the message context. Normal practice in this case would be to use a subclass of OutputStream extending CachedOutputStream. The custom stream will be fed the message and provided the 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 clear="none">
<span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="custom-transport.data/cxf-transport-class-diagram.jpg"></span></p>
<h2 id="CustomTransport-HowitWorks">How it Works</h2>
<p>Interaction between JAX-WS client and service using CXF transport is represented in the following figure:<br clear="none">
<span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="custom-transport.data/cxf-transport.jpg"></span></p>
<h3 id="CustomTransport-SimplifiedClientWorkflow:">Simplified Client Workflow:</h3>
<ul><li>Step1: The JAX-WS client invokes a service, in this manner for example:
<div class="code panel pdl" style="border-style: solid;border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">
URL wsdlURL = this.getClass().getResource("/HelloWorld.wsdl");
HelloWorldService service = new HelloWorldService(wsdlURL, SERVICE_NAME);
HelloWorld hw = service.getHelloWorldPort();
String result = hw.sayHi(TEST_REQUEST); }}
</pre>
</div></div></li><li>Step2: The CXF runtime selects the correct TransportFactory based on some criteria (described below)</li><li>Step3: The CXF runtime calls <em>TransportFactory.getConduit()</em> method to obtain the conduit</li><li>Step4: The CXF runtime invokes <em>Conduit.prepare()</em> and passes the outgoing message as an argument</li><li>Step5: Conduit sets own OutputStream (normally extended CachedOutputStream) as the outgoing message content</li><li>Step6: CXF runtime processes outgoing message, calls the interceptor chain and writes outgoing message to conduit&#8217;s OutputStream stream. Messaging in CXF is stream-oriented; therefore the message normally is proceed and sent not as one bunch, but as a stream. The last bytes of the message can still be in processing by sender, but the first already sent to recipient. Basically it is responsibility of Conduit how to send the message: using streaming or collecting the whole message and send it at once</li><li>Step7: When CXF runtime completely proceeded outgoing message, it invokes <em>Conduit.close(Message)</em> method. It means that the message is completely written into <em>OutputStream</em>. Correspondingly, <em>OutputStream.doClose()</em> method will be called</li><li>Step8: In the <em>doClose()</em> method, Conduit sends the rest of the message (or whole message) to recipient</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 a synchronous or asynchronous manner</li><li>Step11: If a successful 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: If a fault is instead received, the Conduit creates a new Message, sets its context and places it as a 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: Conduit implementation decreases the reference count with the network connection, potentially closing the connection if the count is zero</li><li>Step15: The JAX-WS client code receives the response in sync or async style</li></ul>
<h3 id="CustomTransport-SimplifiedServiceWorkflow:">Simplified Service Workflow:</h3>
<ul><li>Step1: JAX-WS service is registered for example in this way:
<div class="code panel pdl" style="border-style: solid;border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">
HelloWorldImpl serverImpl = new HelloWorldImpl();
Endpoint.publish("udp://localhost:9000/hello", serverImpl);
</pre>
</div></div></li><li>Step2: The CXF runtime selects correct TransportFactory based on some criteria (described below)</li><li>Step3: The CXF runtime calls <em>TransportFactory.getDestination()</em> method to obtain the destination</li><li>Step4: As soon as the CXF runtime activates the endpoint (adds a listener, etc) the <em>Destination.activate()</em> method will be automatically invoked</li><li>Step5: The 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 <em>ChainInitializationObserver</em> object) via <em>incomingObserver.onMessage()</em> about request. Message content is saved as a stream; therefore runtime and business logic can start processing even not completely received message. Normally an incoming connection is saved in a correlation map to be extracted for the sending of appropriate response</li><li>Step7: The business service implementation will be called with the request message in stream form. 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 <em>OutputStream</em> class has access to the marshaled response message and will send this message through the network as a response to the client. In case of streaming, the part of the message can be already sent to the network at this time, and Conduit just sends the last part and closes the sending. Normally incoming connection for specified protocol is cached and created only if necessary</li></ul>
<h2 id="CustomTransport-RegistrationofTransportFactory">Registration of Transport Factory</h2>
<p>There are two ways to register a transport factory: programmatically or via Spring configuration.<br clear="none">
To register transport factory programmatically it is necessary to execute the following code:</p>
<div class="code panel pdl" style="border-style: solid;border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">
Bus bus = BusFactory.getThreadDefaultBus();
DestinationFactoryManagerImpl dfm = bus.getExtension(DestinationFactoryManagerImpl.class);
CustomTransportFactory customTransport = new CustomTransportFactory();
dfm.registerDestinationFactory(TRANSPORT_IDENTIFIER, customTransport);
ConduitInitiatorManager extension = bus.getExtension(ConduitInitiatorManager.class);
extension.registerConduitInitiator(TRANSPORT_IDENTIFIER, customTransport);
</pre>
</div></div>
<p>TRANSPORT_IDENTIFIER is unique transport id (normally in form &#8220;<a shape="rect" class="external-link" href="http://apache.org/transports/PROTOCOL_PREFIX">http://apache.org/transports/PROTOCOL_PREFIX</a>&#8221;).</p>
<p>For Spring configuration, the following could be used instead:</p>
<div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">
&lt;bean class="org.company.cxf.transport.CustomTransportFactory"
lazy-init="false"&gt;
&lt;property name="transportIds"&gt;
&lt;list&gt;
&lt;value&gt;TRANSPORT_IDENTIFIER&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/bean&gt;
</pre>
</div></div>
<h2 id="CustomTransport-TransportFactoryselection">TransportFactory selection</h2>
<p>As far as binding TransportFactory is found, CXF looking for protocol TransportFactory responsible for physical network communication. In this case important is method <em>TransportFactory.getUriPrefixes()</em>. This method returns list of protocol prefixes supported by this TransportFactory. <br clear="none">
When CXF client or service try to communicate using URL with specified protocol prefix (http://, https://, jms://, local://), CXF looks into registered transport factories map and gets the right one for this prefix. If no TransportFactory for this protocol is found, CXF throws corresponded exception.</p>
<p>Client configuration:</p>
<div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">
&lt;jaxws:client id="FlightReservationClient"
xmlns:serviceNamespace="http://www.apache.org/cxf/samples/FlightReservation"
serviceClass="org.apache.cxf.samples.flightreservation.FlightReservation"
serviceName="serviceNamespace:FlightReservationService" endpointName="serviceNamespace:FlightReservationSOAP"&gt;
address="http://localhost:8040/services/FlightReservationService"&gt;
&lt;/jaxws:client&gt;
&#8230;
</pre>
</div></div>
<p>TransportFactory class:</p>
<div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">
&#8230;
private static final Set&lt;String&gt; URI_PREFIXES = new HashSet&lt;String&gt;();
static {
URI_PREFIXES.add("http://");
URI_PREFIXES.add("https:");
}
public Set&lt;String&gt; getUriPrefixes() {
return URI_PREFIXES;
}
</pre>
</div></div>
<h2 id="CustomTransport-ConduitandDestinationLifecycle">Conduit and Destination Lifecycle</h2>
<p>Destinations are normally created by service on startup and released by shutdown. Conduits can be either recreated for each request or cached based on endpoint information for whole client life time. Clients can make concurrent calls to endpoints using different protocols and bound them to different conduits.</p>
<h2 id="CustomTransport-ConcurrencyAspects">Concurrency Aspects</h2>
<p>Conduit and destination objects can by concurrently accessed by multiple threads. Implementations should care about thread safety of the class.</p>
<h2 id="CustomTransport-Streaming">Streaming</h2>
<p>It is strongly recommended to don&#8217;t break streaming in Conduit and Destination implementations, if physical protocol supports it. CXF is completely streaming oriented &#8211; it causes high performance and scalability.</p>
<h2 id="CustomTransport-References">References</h2>
<p>What is the start point to understand the CXF transport layer and implement own transport? It makes sense to read CXF documentation <a shape="rect" href="http://cxf.apache.org/docs/transports.html">CXF transports overview</a> and analyze source code of existing CXF transports (Local and JMS once are more straightforward). They are located into packages: org.apache.cxf.transport.local and org.apache.cxf.transport.jms correspondingly.</p></div>
</div>
<!-- Content -->
</td>
</tr>
</table>
</td>
<td id="cell-2-2" colspan="2">&nbsp;</td>
</tr>
<tr>
<td id="cell-3-0">&nbsp;</td>
<td id="cell-3-1">&nbsp;</td>
<td id="cell-3-2">
<div id="footer">
<!-- Footer -->
<div id="site-footer">
<a href="http://cxf.apache.org/privacy-policy.html">Privacy Policy</a> -
(<a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=27839372">edit page</a>)
(<a href="https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27839372&amp;showComments=true&amp;showCommentArea=true#addcomment">add comment</a>)<br>
Apache CXF, CXF, Apache, the Apache feather logo are trademarks of The Apache Software Foundation.<br>
All other marks mentioned may be trademarks or registered trademarks of their respective owners.
</div>
<!-- Footer -->
</div>
</td>
<td id="cell-3-3">&nbsp;</td>
<td id="cell-3-4">&nbsp;</td>
</tr>
<tr>
<td id="cell-4-0" colspan="2">&nbsp;</td>
<td id="cell-4-1">&nbsp;</td>
<td id="cell-4-2" colspan="2">&nbsp;</td>
</tr>
</table>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
try {
var pageTracker = _gat._getTracker("UA-4458903-1");
pageTracker._trackPageview();
} catch(err) {}</script>
</body>
</html>