Wednesday, May 29, 2013

Datapower XI50 - Dynamic routing to backends with End Points stored in WSRR

Problem

WSRR stores the End Point URLs for the same service. Based on an attribute in the request we would need to route to different backend URLs by looking up WSRR in a Datapower X150 applicance

Solution

The multiple end point URLs are stored as additional properties for a service definition in WSRR. From Datapower XI50 we query WSRR using the REST API provided by WSRR. We get the URLs as addtional properties and route to appropriate URL using DP variable - var://service/routing-url

Querying the WSRR is encapsulated with a seperate XML Firewall Proxy (XMLFW). The main Web Service Proxy (WSP) queries the XMLFW to get the End Point URLs as XML

Addtional IBM documentation - http://www.redbooks.ibm.com/redpapers/pdfs/redp4559.pdf

The XSLT to query the XMLFW is below

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dp="http://www.datapower.com/extensions"
    xmlns:dpconfig="http://www.datapower.com/param/config" xmlns:exsl="http://exslt.org/common"
    extension-element-prefixes="dp dpconfig exsl" exclude-result-prefixes="dp dpconfig exsl">
    <xsl:param name="dpconfig:wsdlName" />
    <xsl:param name="dpconfig:queryWsrrUrl" />
    <xsl:template match="/">
        <xsl:variable name="wsrrResult">
            <dp:url-open target="{$dpconfig:queryWsrrUrl}">
                <querywsrr>
                    <wsdl><xsl:value-of select="$dpconfig:wsdlName"/></wsdl>
                   
                </querywsrr>
            </dp:url-open>
        </xsl:variable>
           
        <xsl:choose>
            <xsl:when
                test="dp:variable('var://context/Backend') = 'Backend1'">
                    <dp:set-variable name="'var://service/routing-url'"
                    value="exsl:node-set($wsrrResult)/resources/resource/properties/property[@name='Backend1_URL']/@value" />
            </xsl:when>
            <xsl:when
                test="dp:variable('var://context/RetrieveAutoPolicyDetailV2/Backend') = 'Backend2'">
                   
                    <dp:set-variable name="'var://service/routing-url'"
                    value="exsl:node-set($wsrrResult)/resources/resource/properties/property[@name='Backend2_URL']/@value" />

            </xsl:when>
            <xsl:when
                test="dp:variable('var://context/RetrieveAutoPolicyDetailV2/Backend') = 'Backend3'">
                    <dp:set-variable name="'var://service/routing-url'"
                    value="exsl:node-set($wsrrResult)/resources/resource/properties/property[@name='Backend3_URL']/@value" />
            </xsl:when>
           
            <xsl:otherwise>
                <dp:set-variable name="'var://service/routing-url'"
                    value="exsl:node-set($wsrrResult)/resources/resource/properties/property[@name='Backend4_URL']/@value" />
            </xsl:otherwise>
        </xsl:choose>

    </xsl:template>
</xsl:stylesheet>

Datapower XI50 - Calling an external URL based on while construct and aggregating data

Problem

The problem occurs from having to aggregate data from an external URL (HTTP, MQ etc) until a particular condition is reached (while construct). This is on a Datapower XI50 appliance

Solution

We can simulate the while construct using a XSLT running on Datapower. The logic for calling the backend (either HTTP, MQ etc) can be encapsulated within a Multi Protocol Gateway (MPGW). The main Web Service Proxy (WSP) has the XSLT as a action which contains the while construct and call the MPGW using datapower extension function url:open()
The XSLT to perform the while construct is below


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:dp="http://www.datapower.com/extensions"
    xmlns:exsl="http://exslt.org/common"
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    extension-element-prefixes="dp exsl" exclude-result-prefixes="dp exsl">

    <xsl:output method="xml" />

    <xsl:template match="/">
        <xsi:element name="test2">
            <xsl:call-template name="dots">
                <!--<xsl:with-param name="result1" select="start" />-->
            </xsl:call-template>
        </xsi:element>
    </xsl:template>

    <xsl:template name="dots">
        <!--<xsl:param name="result1" select="started" />-->
        <!--
            Invoking the HTTP / MQ URL and store it into a XSL Variable
        -->
        <xsl:variable name="tmp">
            <dp:url-open
                target="URL (Can be HTTP or MQ)">
                <xsl:copy-of select="dp:variable('var://context/INPUT')" />
            </dp:url-open>
        </xsl:variable>


        <xsl:copy-of select="$tmp" />


         <xsi:element name="blah">
         <xsl:copy-of select="<COLLECT DATA FROM OUTPUT FROM FIRST CALL>" />
        </xsi:element>
       

        <xsl:if
            test="{CONDITION}">
            <!-- Used for recursion -->
            <xsl:call-template name="dots">
               
                <!--
                    Used for aggregating results by sending back to the loop.
                    <xsl:with-param name="result1" select="concat($result1,$tmp)" />
                -->
            </xsl:call-template>
        </xsl:if>
        <!-- </xsl:if> -->

    </xsl:template>

</xsl:stylesheet>

Datapower XI50 - Applying XPath on CDATA section

Problem 

The CDATA section in a XML is treated as text data and we cannot apply Xpaths on the content of the CDATA section. This causes problems when we have an XML under CDATA section which we want to manipulate using XPath on Datapower XI50 appliance

Solution

The CDATA section under an XML would need to stripped off and added to another XML container. Before we add it, we would need to apply dp:parse() datapower extension function to convert String to Node. Now we can apply any XPath expression for the resulting XML

Sample of the XSLT to strip the CDATA and apply it into another XML is as follows

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:in="http://www.openuri.org/"
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"  
    xmlns:dp="http://www.datapower.com/extensions"   
    extension-element-prefixes="dp"
    exclude-result-prefixes="dp"
    version="1.0">
  <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
  <xsl:template match="/">
  <soapenv:Envelope>
    <soapenv:Header />
         <soapenv:Body>
          <root>
             <!--Optional:-->
             <child>
                <xsl:variable name="inputRequest">
                     <xsl:copy-of select="@*"/>  
                    <xsl:value-of select="." disable-output-escaping="yes" />
                </xsl:variable>
                <xsl:copy-of select="dp:parse($inputRequest)" />
             </child>
          </root>
        </soapenv:Body>
    </soapenv:Envelope>    
</xsl:template>
</xsl:stylesheet>


The resulting XML would be

<root>
    <child>
        <!-- CONTENTS of XML under CDATA SECTION -->
    </child>
</root>

Now we can apply any XPath on this XML to transform it.