Archive

Archive for November, 2012

Versioning SOAP Web Services using a CBR and XSLT

November 21, 2012 Leave a comment

Summary

In this blog post we discuss the evolution of a web service, and how multiple versions of it using the same endpoint can be handled by configuring Membrane ESB to act as an Adapter using XSLT (Extensible Stylesheet Language Transformations).

The Scenario

The scenario is the same as in our previous post, so you should read its first three sections,

  • The Web Service
  • Modifying the Web Service
  • The Core of the Question,

to get to know our “ContactService” as well as the “email” property we added to it after its initial publication.

We again answer the questions posed when we modified the Web Service,

  1. Did we change the published endpoint URL?
  2. Did we change the SOAP namespace URI?

with “no, yes”.

But this time, we take a different approach implementing a solution.

Adapting old Web Service Requests to the New Interface

To avoid having to maintain the old (“v11” or “version 1”) implementation of our Web Service on the backend, we make use of the possibility to transform old requests into new ones:

Given the request

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:con="http://predic8.com/contactService/v11">
  <soapenv:Header/>
  <soapenv:Body>
    <con:addContact>
      <firstname>John</firstname>
      <lastname>Doe</lastname>
    </con:addContact>
  </soapenv:Body>
</soapenv:Envelope>

we add an empty element “email” and change the namespace to “v20”:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:con="http://predic8.com/contactService/v20">
  <soapenv:Header/>
  <soapenv:Body>
    <con:addContact>
      <firstname>John</firstname>
      <lastname>Doe</lastname>
      <email></email>
    </con:addContact>
  </soapenv:Body>
</soapenv:Envelope>

Using XSLT

This transformation can be accomplished automatically using a few lines of XSLT, which we write into a file called v11-to-v20.xslt:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

	<xsl:output omit-xml-declaration="yes" />
	
	<!-- map all old elements to new ones, add add 'email' as child to 'addContact' -->
	<xsl:template match="*[namespace-uri() = 'http://predic8.com/contactService/v11']">
		<xsl:element name="{name()}" namespace="http://predic8.com/contactService/v20">
			<xsl:apply-templates select="node()|@*"/>
			<xsl:if test="local-name() = 'addContact'">
				<xsl:element name="email" />
			</xsl:if>
		</xsl:element>
	</xsl:template>

	<!-- map all old attributes to new ones -->
	<xsl:template match="@*[namespace-uri() = 'http://predic8.com/contactService/v11']">
		<xsl:attribute name="{name()}" namespace="http://predic8.com/contactService/v20">
			<xsl:value-of select="." />
		</xsl:attribute>
	</xsl:template>

	<!-- leave other elements alone -->
	<xsl:template match="*|@*|text()">
		<xsl:copy><xsl:apply-templates select="*|@*|text()"/></xsl:copy>
	</xsl:template>

</xsl:stylesheet> 

Set up Membrane ESB as CBR with XSLT

We now set up Membrane ESB to first distinguish between old and new requests (the same Content Based Router setup as in the previous tutorial). Additionally we tell Membrane to perform the XSLT transformation on the old requests:

For this, we download the distribution from the website, and change conf/proxies.xml to

<proxies xmlns="http://membrane-soa.org/schemas/proxies/v1/"
	 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      	 xsi:schemaLocation="http://membrane-soa.org/schemas/proxies/v1/ http://membrane-soa.org/schemas/proxies/v1/proxies.xsd">

	<soapProxy port="80" wsdl="http://localhost:8080/ContactService/v20?wsdl">
		<path>/ContactService</path>
	    <switch>
	        <case xPath="//*[contains(namespace-uri(), '/contactService/v11')]"
	                service="v11-to-v20" />
	    </switch>
	</soapProxy>
	 
	<soapProxy port="80" wsdl="http://localhost:8080/ContactService/v20?wsdl"
			name="v11-to-v20">
		<path>/ContactService</path>
	    <request>
	        <transform xslt="conf/v11-to-v20.xslt"/>
	    </request>
	</soapProxy>

</proxies>

and put v11-to-v20.xslt into the conf directory.

Done!

(Starting Membrane with memrouter.bat will open port 80 and forward incoming requests to the specified URLs: We assume here that the server implementing the new interfaces is running on localhost:8080/ContactService/v20.

A full working example of the versioned web service together with the CBR+XSLT configuration can be found in examples/versioning/xslt in the distribution archive of Membrane ESB.

Advertisements
Categories: General, Router