blob: 3bf672c191bd5279c14f8e88bace95a83e8e6796 [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 - Service Routing">
<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 -- Service Routing
</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="service-routing.html">Service Routing</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"><h1 id="ServiceRouting-ServiceRouting">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 shape="rect" class="external-link" href="http://activemq.apache.org/camel/">Apache Camel</a> for full support for the <a shape="rect" class="external-link" href="http://activemq.apache.org/camel/enterprise-integration-patterns.html">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 pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">
&lt;wsdl:types&gt;
&lt;schema
targetNamespace="http://apache.org/2007/03/21/hello_world_xml_http/mixed/types"
xmlns="http://www.w3.org/2001/XMLSchema"&gt;
&lt;element name="sayHi"&gt;
&lt;complexType /&gt;
&lt;/element&gt;
..........
&lt;/schema&gt;
&lt;/wsdl:types&gt;
</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 pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" 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 pdl">
<pre class="brush: java; gutter: false; theme: Default">
import javax.xml.ws.Endpoint;
import org.apache.cxf.jaxws.EndpointImpl;
import org.apache.cxf.testutil.common.AbstractBusTestServerBase;
import org.apache.hello_world_mixedstyle.GreeterImplMixedStyle;
public class Server extends AbstractBusTestServerBase {
protected void run() {
//implementor1 and implementor2 are published using local transport
Object implementor1 = new GreeterImplMixedStyle();
String address1 = "local://SoapContext/version1/SoapPort";
Endpoint.publish(address1, implementor1);
Object implementor2 = new GreeterImplMixedStyle();
String address2 = "local://SoapContext/version2/SoapPort";
Endpoint.publish(address2, implementor2);
//A dummy service that acts as a routing mediator
Object implementor = new GreeterImplMixedStyle();
String address = "http://localhost:9027/SoapContext/SoapPort";
javax.xml.ws.Endpoint jaxwsEndpoint = Endpoint.publish(address, implementor);
//Register a MediatorInInterceptor on this dummy service
EndpointImpl jaxwsEndpointImpl = (EndpointImpl)jaxwsEndpoint;
org.apache.cxf.endpoint.Server server = jaxwsEndpointImpl.getServer();
org.apache.cxf.endpoint.Endpoint endpoint = server.getEndpoint();
endpoint.getInInterceptors().add(new MediatorInInterceptor());
}
public static void main(String[] args) {
try {
Server s = new Server();
s.run();
} catch (Exception ex) {
ex.printStackTrace();
System.exit(-1);
} finally {
System.out.println("done!");
}
}
}
</pre>
</div></div>
<div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Example 2: The intermediary interceptor</b></div><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.apache.cxf.Bus;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.SoapVersion;
import org.apache.cxf.binding.soap.SoapVersionFactory;
import org.apache.cxf.bus.CXFBusFactory;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.endpoint.ServerRegistry;
import org.apache.cxf.interceptor.InterceptorChain;
import org.apache.cxf.interceptor.StaxInInterceptor;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.cxf.staxutils.DepthXMLStreamReader;
import org.apache.cxf.staxutils.StaxUtils;
import org.apache.cxf.transport.MessageObserver;
public class MediatorInInterceptor extends AbstractPhaseInterceptor&lt;SoapMessage&gt; {
public MediatorInInterceptor() {
super();
setPhase(Phase.POST_STREAM);
addBefore(StaxInInterceptor.class.getName());
}
public void handleMessage(SoapMessage message) {
String schemaNamespace = "";
InterceptorChain chain = message.getInterceptorChain();
//scan the incoming message for its schema namespace
try {
//create a buffered stream so that we get back the original stream after scaning
InputStream is = message.getContent(InputStream.class);
BufferedInputStream pis = new BufferedInputStream(is);
pis.mark(pis.available());
message.setContent(InputStream.class, pis);
//TODO: process attachements
String encoding = (String)message.get(Message.ENCODING);
XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(pis, encoding);
DepthXMLStreamReader xmlReader = new DepthXMLStreamReader(reader);
if (xmlReader.nextTag() == XMLStreamConstants.START_ELEMENT) {
String ns = xmlReader.getNamespaceURI();
SoapVersion soapVersion = SoapVersionFactory.getInstance().getSoapVersion(ns);
//advance just past header
StaxUtils.toNextTag(xmlReader, soapVersion.getBody());
//past body.
xmlReader.nextTag();
}
schemaNamespace = xmlReader.getName().getNamespaceURI();
pis.reset();
} catch (IOException e) {
e.printStackTrace();
} catch (XMLStreamException e) {
e.printStackTrace();
}
//Look up for all available endpoints registered on the bus
Bus bus = CXFBusFactory.getDefaultBus();
ServerRegistry serverRegistry = bus.getExtension(ServerRegistry.class);
List&lt;Server&gt; servers = serverRegistry.getServers();
//if the incoming message has a namespace contained "2007/03/21", we redirect the message
//to the new version of service on endpoint "local://localhost:9027/SoapContext/version2/SoapPort"
Server targetServer = null;
for (Server server : servers) {
targetServer = server;
String address = server.getEndpoint().getEndpointInfo().getAddress();
if (schemaNamespace.indexOf("2007/03/21") != -1) {
if (address.indexOf("version2") != -1) {
break;
}
} else if (address.indexOf("version1") != -1) {
break;
}
}
//Redirect the request
MessageObserver mo = targetServer.getMessageObserver();
mo.onMessage(message);
//Now the response has been put in the message, abort the chain
chain.abort();
}
}</pre>
</div></div>
<p>A few things to note:</p>
<ol><li>The <code>MediatorInInterceptor</code> is for SOAP binding, you can write a similar interceptor for XML binding etc.</li><li>We call <code>chain.abort</code> at the end of this interceptor to stop any further processing in the dummy service.</li><li>In this example, <code>implementor1</code> and <code>implementor2</code> are published using local transport. This is achieved by using an address like "local://SoapContext/version1/SoapPort". The <code>MediatorInInterceptor</code> looks up <code>ServerRegistry</code> to find endpoints hosted in the server then does the re-dispatch.</li><li>The <code>MediatorInInterceptor</code> is set to <code>POST_STREAM</code> phase and before <code>StaxInInterceptor</code>, this makes sure it is the very first interceptor to be invoked.</li></ol></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=49775">edit page</a>)
(<a href="https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=49775&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>