Saturday, February 19, 2011

Handling a http-get request and invoking an external Web service with WSO2 ESB

Following post will discuss how to handle a http-get request from WSO2 ESB and call a external web service. Inorder to clarify example clearly I am using a simple usecase described below. The relevant configuration files, steps to run the sample and the messages flowing through the system is shown below. I have labeled the messages in the diagram, inorder to show the contents of the messages.

Usecase
1. Client makes a rest-like http-get: GET /.../company/<id>
eg. curl "http://localhost:8280/services/ProxyA/company/IBM" -v
2. ESB service proxy picks the company id from the url
eg. IBM
3. ESB service makes a web service call to a external ws-service (SimpleStockQuoteService) and a spesific ws-method.
4. ESB service parses the ws-response and returns a plain xml result to the client.

Configuration Files
Following is the Synapse configuration which contains the sample proxy which handles the request.
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://ws.apache.org/ns/synapse">
<registry provider="org.wso2.carbon.mediation.registry.WSO2Registry">
<parameter name="cachableDuration">15000</parameter>
</registry>
<proxy name="ProxyA" transports="https http" startOnLoad="true" trace="disable">
<target>
<inSequence>
<enrich>
<source type="inline">
<a xmlns=""/>
</source>
<target type="body" action="child"/>
</enrich>
<log level="full"/>
<property name="company" expression="substring-after(get-property('To'),'company/')"/>
<xslt key="xslt-transform-request">
<property name="symbol" expression="get-property('company')"/>
</xslt>
<header name="Action" value="urn:getQuote"/>
<log level="full"/>
<send>
<endpoint name="ep1">
<address uri="http://localhost:9000/services/SimpleStockQuoteService" format="soap11"/>
</endpoint>
</send>
</inSequence>
<outSequence>
<property xmlns:ax21="http://services.samples/xsd" xmlns:ns="http://services.samples" name="response_symbol" expression="//ns:return/ax21:symbol/child::text()"/>
<property xmlns:ax21="http://services.samples/xsd" xmlns:ns="http://services.samples" name="response_high" expression="//ns:return/ax21:high/child::text()"/>
<property xmlns:ax21="http://services.samples/xsd" xmlns:ns="http://services.samples" name="response_low" expression="//ns:return/ax21:low/child::text()"/>
<log level="custom">
<property name="response symbol:" expression="get-property('response_symbol')"/>
<property name="response high :" expression="get-property('response_high')"/>
<property name="response low :" expression="get-property('response_low')"/>
</log>
<xslt key="xslt-transform-response">
<property name="symbol" expression="get-property('response_symbol')"/>
<property name="high" expression="get-property('response_high')"/>
<property name="low" expression="get-property('response_low')"/>
</xslt>
<send/>
</outSequence>
</target>
</proxy>
<localEntry key="xslt-transform-request" src="file:repository/samples/resources/transform/request_transform.xslt"/>
<localEntry key="xslt-transform-response" src="file:repository/samples/resources/transform/response_transform.xslt"/>
<sequence name="fault">
<log level="full">
<property name="MESSAGE" value="Executing default 'fault' sequence"/>
<property name="ERROR_CODE" expression="get-property('ERROR_CODE')"/>
<property name="ERROR_MESSAGE" expression="get-property('ERROR_MESSAGE')"/>
</log>
<drop/>
</sequence>
<sequence name="main">
<in>
<log level="full"/>
<filter source="get-property('To')" regex="http://localhost:9000.*">
<send/>
</filter>
</in>
<out>
<send/>
</out>
</sequence>
</definitions>

Following is the xslt transformation (request_transform.xslt) which transforms the request at the ESB.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:param name="symbol"/>
<xsl:template match="/">
<m0:getQuote xmlns:m0="http://services.samples">
<m0:request>
<m0:symbol><xsl:value-of select="$symbol"/></m0:symbol>
</m0:request>
</m0:getQuote>
</xsl:template>
</xsl:stylesheet>

Following is the xslt transformation (response_transform.xslt) which transforms the response at the ESB.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:param name="symbol"/>
<xsl:param name="high"/>
<xsl:param name="low"/>
<xsl:template match="/">
<m0:getQuote xmlns:m0="http://services.samples">
<m0:response>
<m0:company><xsl:value-of select="$symbol"/></m0:company>
<m0:high><xsl:value-of select="$high"/></m0:high>
<m0:low><xsl:value-of select="$low"/></m0:low>
</m0:response>
</m0:getQuote>
</xsl:template>
</xsl:stylesheet>

The contents of the messages flowing through the ESB
Request-A
GET /services/ProxyA/company/IBM HTTP/1.1
User-Agent: curl/7.21.0 (x86_64-pc-linux-gnu) libcurl/7.21.0 OpenSSL/0.9.8o zlib/1.2.3.4 libidn/1.18
Host: 127.0.0.1:8281
Accept: */*
Request-B
POST /services/SimpleStockQuoteService HTTP/1.1
Content-Type: text/xml; charset=UTF-8
Accept: */*
SOAPAction: "urn:getQuote"
Transfer-Encoding: chunked
Host: 127.0.0.1:9001
Connection: Keep-Alive
User-Agent: Synapse-HttpComponents-NIO

113
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:envelope soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:body>
<m0:getquote m0="http://services.samples">
<m0:request>
<m0:symbol>IBM</m0:symbol>
</m0:request>
</m0:getQuote>
</soapenv:Body>
</soapenv:Envelope>0
Response-C
HTTP/1.1 200 OK
Content-Type: text/xml; charset=UTF-8
Date: Sat, 19 Feb 2011 08:50:01 GMT
Transfer-Encoding: chunked
Connection: Keep-Alive

40a
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:envelope soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:body>
<ns:getquoteresponse ns="http://services.samples">
<ns:return ax21="http://services.samples/xsd" xsi="http://www.w3.org/2001/XMLSchema-instance" type="ax21:GetQuoteResponse">
<ax21:change>-2.7502820955517455</ax21:change>
<ax21:earnings>13.682776182003703</ax21:earnings>
<ax21:high>159.3075652956029</ax21:high>
<ax21:last>154.1201005301602</ax21:last>
<ax21:lasttradetimestamp>Sat Feb 19 14:20:01 IST 2011</ax21:lastTradeTimestamp>
<ax21:low>158.77156450332262</ax21:low>
<ax21:marketcap>-4211789.232304155</ax21:marketCap>
<ax21:name>IBM Company</ax21:name>
<ax21:open>161.05685744490376</ax21:open>
<ax21:peratio>24.219012038564948</ax21:peRatio>
<ax21:percentagechange>1.913224112346585</ax21:percentageChange>
<ax21:prevclose>-143.75117257844414</ax21:prevClose>
<ax21:symbol>IBM</ax21:symbol>
<ax21:volume>6450</ax21:volume>
</ns:return>
</ns:getQuoteResponse>
</soapenv:Body>
</soapenv:Envelope>0
Response-D
HTTP/1.1 200 OK
Content-Type: application/xml; charset=UTF-8
Date: Sat, 19 Feb 2011 08:50:01 GMT
Transfer-Encoding: chunked

bc
<m0:getquote m0="http://services.samples">
<m0:response>
<m0:company>IBM</m0:company>
<m0:high>159.3075652956029</m0:high>
<m0:low>158.77156450332262</m0:low>
</m0:response></m0:getQuote>0

Steps to run the sample
1) Download WSO2 ESB [1].

2) Start wso2esb using the startup scripts.
eg: ./wso2server.sh

3) Login to the WSO2 Management console.

4) Copy the attached xslt files (ie. request_transform.xslt, response_transform.xslt) to wso2esb-3.0.1/repository/samples/resources/transform directory.

5) Go to Source View and paste the Synapse configuration to it and hit update.

6) Start the Axis2 server and deploy the SimpleStockQuoteService if not already done.
i) Run the ant script to build the SimpleStockQuoteService. It is residing in wso2esb-3.0.1/samples/axis2Server/src/SimpleStockQuoteService directory.
ii) Then run the simple axis2Server shipped in with the wso2esb. This can be done by the running the axis2Server startup script inside wso2esb-3.0.1/samples/axis2Server/ directory.
eg: ./axis2server.sh

7) Execute the following curl command.
eg: curl "http://localhost:8280/services/ProxyA/company/IBM" -v

Then you will be getting the following response.
eg:

* About to connect() to localhost port 8280 (#0)
* Trying ::1... connected
* Connected to localhost (::1) port 8280 (#0)
> GET /services/ProxyA/company/IBM HTTP/1.1
> User-Agent: curl/7.21.0 (x86_64-pc-linux-gnu) libcurl/7.21.0 OpenSSL/0.9.8o zlib/1.2.3.4 libidn/1.18
> Host: localhost:8280
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/xml; charset=UTF-8
< Date: Thu, 10 Feb 2011 07:54:46 GMT
< Transfer-Encoding: chunked
<
* Connection #0 to host localhost left intact
* Closing connection #0
<m0:getQuote xmlns:m0="http://services.samples"><m0:response><m0:company>IBM</m0:company><m0:high>-81.16785748190335</m0:high><m0:low>85.09674577550493</m0:low></m0:response></m0:getQuote>
References
[1] - http://wso2.org/downloads/esb
[2] - http://wso2.org/project/esb/java/3.0.1/docs/

3 comments:

spajic said...

Hello!
Thank you for a great post!

I have a question..
I made a data service with WSO2 DSS. It can handle rest-like requests like services/person/get_name?id=1000 and give http response in xml.

1. Can WSO2 add a parameter to response header? (like "Access-Control-Allow-Origin":"*")
2. Can WSO2 return results in JSON?

Thank You!

Unknown said...

How do you know the response from External Web Service (Response-C)? You make your outSequence configuration based in Response-C but i don't understand how you know this, I am using JBoss as application server and this doesn't return a SOAP message visible, How do I get this?

Unknown said...

aHow do you know the response from External Web Service (Response-C)? You make your outSequence configuration based in Response-C but i don't understand how you know this, I am using JBoss as application server and this doesn't return a SOAP message visible, How do I get this?