cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache CXF Documentation > Service Routing
Date Tue, 15 Jan 2013 12:17:00 GMT
<html>
<head>
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/2042/9/1/_/styles/combined.css?spaceKey=CXF20DOC&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/CXF20DOC/Service+Routing">Service
Routing</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~coheigea@apache.org">Colm
O hEigeartaigh</a>
    </h4>
        <br/>
                         <h4>Changes (4)</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>{code:xml} <br></td></tr>
            <tr><td class="diff-unchanged" >&lt;wsdl:types&gt;
   &lt;schema
      targetNamespace=&quot;http://apache.org/2007/03/21/hello_world_xml_http/mixed/types&quot;
      xmlns=&quot;http://www.w3.org/2001/XMLSchema&quot;&gt;
      &lt;element name=&quot;sayHi&quot;&gt;
         &lt;complexType /&gt;
      &lt;/element&gt;   <br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">
</span> <span class="diff-added-words"style="background-color: #dfd;">..........</span>
<br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">..........</span>
<span class="diff-added-words"style="background-color: #dfd;">&lt;/schema&gt;</span>
<br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">
</span> <span class="diff-added-words"style="background-color: #dfd;">&lt;/wsdl:types&gt;</span>
<br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">
        &lt;/schema&gt; <br>    &lt;/wsdl:types&gt; <br></td></tr>
            <tr><td class="diff-unchanged" >{code} <br> <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
    
            </table>
    </div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <h1><a name="ServiceRouting-ServiceRouting"></a>Service Routing</h1>

<p>One thing you'll often need to do when developing services, is to develop a new version
while keeping the old version running. This guide shows how to develop a simple service router
that will scan the incoming message then direct the message to the appropriate service version.</p>

<p>For more complex requirements you might also wish to check out <a href="http://activemq.apache.org/camel/"
class="external-link" rel="nofollow">Apache Camel</a> for full support for the <a
href="http://activemq.apache.org/camel/enterprise-integration-patterns.html" class="external-link"
rel="nofollow">Enterprise Integration Patterns with CXF</a></p>

<p>One common practice to version web services is using XML namespaces to clearly delineate
the versions of a document that are compatible. For example:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;wsdl:types&gt;</span>
   &lt;schema
      targetNamespace=<span class="code-quote">"http://apache.org/2007/03/21/hello_world_xml_http/mixed/types"</span>
      xmlns=<span class="code-quote">"http://www.w3.org/2001/XMLSchema"</span>&gt;
      <span class="code-tag">&lt;element name=<span class="code-quote">"sayHi"</span>&gt;</span>
         <span class="code-tag">&lt;complexType /&gt;</span>
      <span class="code-tag">&lt;/element&gt;</span>  
      ..........     
   <span class="code-tag">&lt;/schema&gt;</span>
<span class="code-tag">&lt;/wsdl:types&gt;</span>
</pre>
</div></div>

<p>Among many different possible implementations of service routing, one simple way
("simple" in terms of amount of code you have to write, but it does require a certain extent
of familiarity with CXF internal architecture) to do this is by writing a CXF interceptor
that acts as a routing mediator. </p>

<p>Firstly we need to have a dummy service with an intermediary interceptor registered.
This intermediary interceptor sits at the very beginning of the interceptor chain, this is
to make sure the intermediary interceptor is the first interceptor being invoked in the message
pipeline. The intermediary interceptor scans the incoming message for example, the schema
namespace, then directs the message to the desired endpoint according to user programmed strategy.
</p>

<p>Lets see the code:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader"
style="border-bottom-width: 1px;"><b>Example 1: The server - this server has three
endpoints: one endpoint for the dummy service, another two endpoints are different versions
of Greeter service</b></div><div class="codeContent panelContent">
<pre class="code-java">

<span class="code-keyword">import</span> javax.xml.ws.Endpoint;

<span class="code-keyword">import</span> org.apache.cxf.jaxws.EndpointImpl;
<span class="code-keyword">import</span> org.apache.cxf.testutil.common.AbstractBusTestServerBase;
<span class="code-keyword">import</span> org.apache.hello_world_mixedstyle.GreeterImplMixedStyle;


<span class="code-keyword">public</span> class Server <span class="code-keyword">extends</span>
AbstractBusTestServerBase {

    <span class="code-keyword">protected</span> void run() {
        <span class="code-comment">//implementor1 and implementor2 are published using
local transport
</span>        <span class="code-object">Object</span> implementor1 = <span
class="code-keyword">new</span> GreeterImplMixedStyle();
        <span class="code-object">String</span> address1 = <span class="code-quote">"local:<span
class="code-comment">//SoapContext/version1/SoapPort"</span>;
</span>        Endpoint.publish(address1, implementor1);

        <span class="code-object">Object</span> implementor2 = <span class="code-keyword">new</span>
GreeterImplMixedStyle();
        <span class="code-object">String</span> address2 = <span class="code-quote">"local:<span
class="code-comment">//SoapContext/version2/SoapPort"</span>;
</span>        Endpoint.publish(address2, implementor2);
        
        <span class="code-comment">//A dummy service that acts as a routing mediator
</span>        <span class="code-object">Object</span> implementor = <span
class="code-keyword">new</span> GreeterImplMixedStyle();
        <span class="code-object">String</span> address = <span class="code-quote">"http:<span
class="code-comment">//localhost:9027/SoapContext/SoapPort"</span>;
</span>        javax.xml.ws.Endpoint jaxwsEndpoint = Endpoint.publish(address, implementor);
 
        
        <span class="code-comment">//Register a MediatorInInterceptor on <span class="code-keyword">this</span>
dummy service
</span>        EndpointImpl jaxwsEndpointImpl = (EndpointImpl)jaxwsEndpoint;
        org.apache.cxf.endpoint.Server server = jaxwsEndpointImpl.getServer();
        org.apache.cxf.endpoint.Endpoint endpoint = server.getEndpoint();
        endpoint.getInInterceptors().add(<span class="code-keyword">new</span>
MediatorInInterceptor());
    }

    <span class="code-keyword">public</span> <span class="code-keyword">static</span>
void main(<span class="code-object">String</span>[] args) {
        <span class="code-keyword">try</span> {
            Server s = <span class="code-keyword">new</span> Server();
            s.run();
        } <span class="code-keyword">catch</span> (Exception ex) {
            ex.printStackTrace();
            <span class="code-object">System</span>.exit(-1);
        } <span class="code-keyword">finally</span> {
            <span class="code-object">System</span>.out.println(<span class="code-quote">"done!"</span>);
        }
    }
}
</pre>
</div></div>

<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader"
style="border-bottom-width: 1px;"><b>Example 2: The intermediary interceptor</b></div><div
class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">import</span> java.io.BufferedInputStream;
<span class="code-keyword">import</span> java.io.IOException;
<span class="code-keyword">import</span> java.io.InputStream;
<span class="code-keyword">import</span> java.util.List;

<span class="code-keyword">import</span> javax.xml.stream.XMLInputFactory;
<span class="code-keyword">import</span> javax.xml.stream.XMLStreamConstants;
<span class="code-keyword">import</span> javax.xml.stream.XMLStreamException;
<span class="code-keyword">import</span> javax.xml.stream.XMLStreamReader;

<span class="code-keyword">import</span> org.apache.cxf.Bus;
<span class="code-keyword">import</span> org.apache.cxf.binding.soap.SoapMessage;
<span class="code-keyword">import</span> org.apache.cxf.binding.soap.SoapVersion;
<span class="code-keyword">import</span> org.apache.cxf.binding.soap.SoapVersionFactory;
<span class="code-keyword">import</span> org.apache.cxf.bus.CXFBusFactory;
<span class="code-keyword">import</span> org.apache.cxf.endpoint.Server;
<span class="code-keyword">import</span> org.apache.cxf.endpoint.ServerRegistry;
<span class="code-keyword">import</span> org.apache.cxf.interceptor.InterceptorChain;
<span class="code-keyword">import</span> org.apache.cxf.interceptor.StaxInInterceptor;
<span class="code-keyword">import</span> org.apache.cxf.message.Message;
<span class="code-keyword">import</span> org.apache.cxf.phase.AbstractPhaseInterceptor;
<span class="code-keyword">import</span> org.apache.cxf.phase.Phase;
<span class="code-keyword">import</span> org.apache.cxf.staxutils.DepthXMLStreamReader;
<span class="code-keyword">import</span> org.apache.cxf.staxutils.StaxUtils;
<span class="code-keyword">import</span> org.apache.cxf.transport.MessageObserver;


<span class="code-keyword">public</span> class MediatorInInterceptor <span
class="code-keyword">extends</span> AbstractPhaseInterceptor&lt;SoapMessage&gt;
{

    <span class="code-keyword">public</span> MediatorInInterceptor() {
        <span class="code-keyword">super</span>();
        setPhase(Phase.POST_STREAM);
        addBefore(StaxInInterceptor.class.getName());
    }

    <span class="code-keyword">public</span> void handleMessage(SoapMessage message)
{
        <span class="code-object">String</span> schemaNamespace = "";
        InterceptorChain chain = message.getInterceptorChain();

        <span class="code-comment">//scan the incoming message <span class="code-keyword">for</span>
its schema namespace
</span>        <span class="code-keyword">try</span> {
            <span class="code-comment">//create a buffered stream so that we get back
the original stream after scaning
</span>            InputStream is = message.getContent(InputStream.class);
            BufferedInputStream pis = <span class="code-keyword">new</span> BufferedInputStream(is);
            pis.mark(pis.available());
            message.setContent(InputStream.class, pis);

            <span class="code-comment">//TODO: process attachements
</span>
            <span class="code-object">String</span> encoding = (<span class="code-object">String</span>)message.get(Message.ENCODING);
            XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(pis,
encoding);
            DepthXMLStreamReader xmlReader = <span class="code-keyword">new</span>
DepthXMLStreamReader(reader);

            <span class="code-keyword">if</span> (xmlReader.nextTag() == XMLStreamConstants.START_ELEMENT)
{
                <span class="code-object">String</span> ns = xmlReader.getNamespaceURI();
                SoapVersion soapVersion = SoapVersionFactory.getInstance().getSoapVersion(ns);
                <span class="code-comment">//advance just past header
</span>                StaxUtils.toNextTag(xmlReader, soapVersion.getBody());
                <span class="code-comment">//past body.
</span>                xmlReader.nextTag();
            }

            schemaNamespace = xmlReader.getName().getNamespaceURI();

            pis.reset();
        } <span class="code-keyword">catch</span> (IOException e) {
            e.printStackTrace();
        } <span class="code-keyword">catch</span> (XMLStreamException e) {
            e.printStackTrace();
        }

        <span class="code-comment">//Look up <span class="code-keyword">for</span>
all available endpoints registered on the bus
</span>        Bus bus = CXFBusFactory.getDefaultBus();
        ServerRegistry serverRegistry = bus.getExtension(ServerRegistry.class);
        List&lt;Server&gt; servers = serverRegistry.getServers();

        <span class="code-comment">//<span class="code-keyword">if</span>
the incoming message has a namespace contained <span class="code-quote">"2007/03/21"</span>,
we redirect the message
</span>        <span class="code-comment">//to the <span class="code-keyword">new</span>
version of service on endpoint <span class="code-quote">"local://localhost:9027/SoapContext/version2/SoapPort"</span>
</span>        Server targetServer = <span class="code-keyword">null</span>;
        <span class="code-keyword">for</span> (Server server : servers) {
            targetServer = server;
            <span class="code-object">String</span> address = server.getEndpoint().getEndpointInfo().getAddress();
            <span class="code-keyword">if</span> (schemaNamespace.indexOf(<span
class="code-quote">"2007/03/21"</span>) != -1) {
                <span class="code-keyword">if</span> (address.indexOf(<span
class="code-quote">"version2"</span>) != -1) {
                    <span class="code-keyword">break</span>;
                }
            } <span class="code-keyword">else</span> <span class="code-keyword">if</span>
(address.indexOf(<span class="code-quote">"version1"</span>) != -1) {
                <span class="code-keyword">break</span>;
            }
        }

        <span class="code-comment">//Redirect the request
</span>        MessageObserver mo = targetServer.getMessageObserver();
        mo.onMessage(message);

        <span class="code-comment">//Now the response has been put in the message, abort
the chain 
</span>        chain.abort();
    }

}</pre>
</div></div>


<p>A few things to note:</p>

<ol>
	<li>The <tt>MediatorInInterceptor</tt> is for SOAP binding, you can write
a similar interceptor for XML binding etc.</li>
	<li>We call <tt>chain.abort</tt> at the end of this interceptor to stop
any further processing in the dummy service.</li>
	<li>In this example, <tt>implementor1</tt> and <tt>implementor2</tt>
are published using local transport. This is achieved by using an address like "local://SoapContext/version1/SoapPort".
The <tt>MediatorInInterceptor</tt> looks up <tt>ServerRegistry</tt>
to find endpoints hosted in the server then does the re-dispatch.</li>
	<li>The <tt>MediatorInInterceptor</tt> is set to <tt>POST_STREAM</tt>
phase and before <tt>StaxInInterceptor</tt>, this makes sure it is the very first
interceptor to be invoked.</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/CXF20DOC/Service+Routing">View
Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=49775&revisedVersion=11&originalVersion=10">View
Changes</a>
                |
        <a href="https://cwiki.apache.org/confluence/display/CXF20DOC/Service+Routing?showComments=true&amp;showCommentArea=true#addcomment">Add
Comment</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message