2017-02-10 2 views
0

Ich habe versucht, herauszufinden, wie WSO2 ESB Aufrufe an zwei verschiedene APIs aufrufen und ihre Ergebnisse in einer einzigen Antwort kombinieren und in nichts als Ärger laufen. Im Grunde habe ich zwei Backends bekam ich mache Anfragen darauf reagieren etwas wie folgt aus:Kombinieren Sie zwei Abfragen mithilfe von WSO2 ESB

http://example.com/items:

<?xml version="1.0" encoding="UTF-8"?> 
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <soapenv:Body> 
     <response xmlns="http://example.com/response"> 
      <query name="items" xmlns="http://example.com/query"> 
       <row> 
        <id>1</id> 
        <name>Item 1</name> 
       </row> 
       <row> 
        <id>2</id> 
        <name>Item 2</name> 
       </row> 
      </query> 
     </response> 
    </soapenv:Body> 
</soapenv:Envelope> 

http://example.com/parts:

<?xml version="1.0" encoding="UTF-8"?> 
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <soapenv:Body> 
     <response xmlns="http://example.com/response"> 
      <query name="parts" xmlns="http://example.com/query"> 
       <row> 
        <id>1</id> 
        <part>Part 1.1</part> 
       </row> 
       <row> 
        <id>1</id> 
        <part>Part 1.2</part> 
       </row> 
       <row> 
        <id>1</id> 
        <part>Part 1.3</part> 
       </row> 
       <row> 
        <id>2</id> 
        <part>Part 2.1</part> 
       </row> 
       <row> 
        <id>2</id> 
        <part>Part 2.2</part> 
       </row> 
      </query> 
     </response> 
    </soapenv:Body> 
</soapenv:Envelope> 

I Möchte beide Anfragen stellen und dann ihre Ergebnisse so kombinieren, dass sie in etwa so aussehen:

<items> 
    <item> 
     <id>1</id> 
     <name>Item 1</name> 
     <parts> 
      <part> 
       <id>1</id> 
       <name>Part 1.1</name> 
      </part> 
      <part> 
       <id>1</id> 
       <name>Part 1.2</name> 
      </part> 
      <part> 
       <id>1</id> 
       <name>Part 1.3</name> 
      </part> 
     </parts> 
    </item> 
    <item> 
     <id>2</id> 
     <name>Item 2</name> 
     <parts> 
      <part> 
       <id>2</id> 
       <name>Part 2.1</name> 
      </part> 
      <part> 
       <id>2</id> 
       <name>Part 2.2</name> 
      </part> 
     </parts> 
    </item> 
</items> 

Grundsätzlich hat jede Antwort von beiden APIs eine Liste von row s, von denen jede ein id Element enthält. Die id s im Aufruf an /items sind innerhalb dieser Antwort eindeutig, und jede Zeile in der Antwort von parts hat eine id, die es an eine Zeile von /items bindet.

Ich habe die folgende API-Definition in der ESB bekam:

<?xml version="1.0" encoding="UTF-8"?> 
<api context="/item_list" name="ItemList" xmlns="http://ws.apache.org/ns/synapse"> 
    <resource methods="POST" uri-template="/"> 
     <inSequence> 
      <header name="Content-Type" scope="transport" value="text/xml; charset=utf-8"/> 
      <clone> 
       <target> 
        <sequence> 
         <send> 
          <endpoint> 
           <address format="soap11" uri="http://example.com/items"/> 
          </endpoint> 
         </send> 
        </sequence> 
       </target> 
       <target> 
        <sequence> 
         <send> 
          <endpoint> 
           <address format="soap11" uri="http://example.com/parts"/> 
          </endpoint> 
         </send> 
        </sequence> 
       </target> 
      </clone> 
     </inSequence> 
     <outSequence> 
      <aggregate> 
       <correlateOn expression="//*[name()='response']/*[name()='query']/*[name()='row']/*[name()='id']" /> 
       <completeCondition> 
        <messageCount max="2" min="2"/> 
       </completeCondition> 
       <onComplete expression="//*[name()='response']/*[name()='query']/*[name()='row']"> 
        <send/> 
       </onComplete> 
      </aggregate> 
     </outSequence> 
     <faultSequence/> 
    </resource> 
</api> 

Die inSequence hier stark vereinfacht ist, aber es hat zwei gültige Anfragen senden und die erwarteten Antworten zurückkommt. Die outSequence, wie sie hier geschrieben wird, sendet niemals eine Antwort an den Client oder protokolliert einen Fehler auf dem Server. Wenn ich das Element correlateOn von aggregate entferne, bekomme ich scheinbar zufällig eine einzelne row von einem der zwei API-Aufrufe zurück. I denke,correlateOn ist etwas, was ich hier verwenden möchte, aber ich kann keine nützliche Dokumentation von WSO2 oder Apache finden, also bin ich mir sicher, dass ich es falsch verwende. Mein XPath-Hintergrund ist ziemlich schwach, also bin ich mir sicher, dass dieser Ausdruck auch etwas Arbeit gebrauchen könnte.

Bin ich hier wenigstens mit dem Klon/Aggregat-Muster auf dem richtigen Weg? Wie würde ich die Ergebnisse dieser beiden Abfragen in etwas Ähnliches wie in meinem Beispiel kombinieren? Wenn ich etwas auch nur annähernd erreichen kann, sollte ich den Rest mit XSLT erledigen können.

Antwort

4

werfen Sie einen Blick auf diese Demo:

Backend 1 mit den Einzelteilen Antwort:

<?xml version="1.0" encoding="UTF-8"?> 
<proxy xmlns="http://ws.apache.org/ns/synapse" 
     name="items" 
     transports="https http" 
     startOnLoad="true"> 
    <target> 
     <inSequence> 
     <payloadFactory media-type="xml"> 
      <format> 
       <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
           xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
           xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
        <soapenv:Body> 
        <response xmlns="http://example.com/response"> 
         <query xmlns="http://example.com/query" name="items"> 
          <row> 
           <id>1</id> 
           <name>Item 1</name> 
          </row> 
          <row> 
           <id>2</id> 
           <name>Item 2</name> 
          </row> 
         </query> 
        </response> 
        </soapenv:Body> 
       </soapenv:Envelope> 
      </format> 
      <args/> 
     </payloadFactory> 
     <log level="full"/> 
     <loopback/> 
     </inSequence> 
     <outSequence> 
     <send/> 
     </outSequence> 
     <faultSequence/> 
    </target> 
</proxy> 

Backend 2 mit den Teilen Antwort:

<?xml version="1.0" encoding="UTF-8"?> 
<proxy xmlns="http://ws.apache.org/ns/synapse" 
     name="parts" 
     transports="https http" 
     startOnLoad="true"> 
    <target> 
     <inSequence> 
     <payloadFactory media-type="xml"> 
      <format> 
       <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
           xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
           xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
        <soapenv:Body> 
        <response xmlns="http://example.com/response"> 
         <query xmlns="http://example.com/query" name="parts"> 
          <row> 
           <id>1</id> 
           <part>Part 1.1</part> 
          </row> 
          <row> 
           <id>1</id> 
           <part>Part 1.2</part> 
          </row> 
          <row> 
           <id>1</id> 
           <part>Part 1.3</part> 
          </row> 
          <row> 
           <id>2</id> 
           <part>Part 2.1</part> 
          </row> 
          <row> 
           <id>2</id> 
           <part>Part 2.2</part> 
          </row> 
         </query> 
        </response> 
        </soapenv:Body> 
       </soapenv:Envelope> 
      </format> 
      <args/> 
     </payloadFactory> 
     <log level="full"/> 
     <loopback/> 
     </inSequence> 
     <outSequence> 
     <send/> 
     </outSequence> 
     <faultSequence/> 
    </target> 
</proxy> 

Mein API-Backend Aufruf 1 und Backend 2 und Transformieren mit xslt:

<?xml version="1.0" encoding="UTF-8"?> 
<api xmlns="http://ws.apache.org/ns/synapse" 
    name="ItemList" 
    context="/item_list"> 
    <resource methods="POST" uri-template="/"> 
     <inSequence> 
     <header name="Action" scope="default" value="urn:mediate"/> 
     <call> 
      <endpoint> 
       <address uri="http://localhost:8283/services/items.itemsHttpSoap11Endpoint" 
         format="soap11"/> 
      </endpoint> 
     </call> 
     <enrich> 
      <source type="inline" clone="true"> 
       <Payloads/> 
      </source> 
      <target type="property" property="Items"/> 
     </enrich> 
     <enrich> 
      <source clone="true" xpath="$body/*"/> 
      <target action="child" xpath="$ctx:Items"/> 
     </enrich> 
     <payloadFactory media-type="xml"> 
      <format> 
       <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
           xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
           xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
        <soapenv:Body/> 
       </soapenv:Envelope> 
      </format> 
      <args/> 
     </payloadFactory> 
     <call> 
      <endpoint> 
       <address uri="http://localhost:8283/services/parts.partsHttpSoap11Endpoint" 
         format="soap11"/> 
      </endpoint> 
     </call> 
     <enrich> 
      <source clone="true" xpath="$body/*[name()='response']/*[name()='query']"/> 
      <target type="property" property="Parts"/> 
     </enrich> 
     <enrich> 
      <source type="property" clone="true" property="Parts"/> 
      <target action="child" xpath="$ctx:Items"/> 
     </enrich> 
     <enrich> 
      <source type="property" property="Items"/> 
      <target type="body"/> 
     </enrich> 
     <xslt key="transformTwoSourcesToOneResult"/>    
     <loopback/> 
     </inSequence> 
     <outSequence> 
     <send/> 
     </outSequence> 
     <faultSequence/> 
    </resource> 
</api> 

Und meine XSLT-Transformation:

<?xml version="1.0" encoding="UTF-8"?> 
<localEntry key="transformTwoSourcesToOneResult" xmlns="http://ws.apache.org/ns/synapse"> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
           xmlns:ns0="http://example.com/query" 
           xmlns:ns1="http://example.com/response" 
           xmlns:xs="http://www.w3.org/2001/XMLSchema" 
           xmlns:exslt="http://exslt.org/common" 
           xmlns:saxon="http://saxon.sf.net/" 
           xmlns:syn="http://ws.apache.org/ns/synapse" 
           exclude-result-prefixes="ns0 ns1 xs"> 
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/> 
    <xsl:template match="/"> 
    <xsl:variable name="var1_instance_Payloads" select="."/> 
     <items> 
      <xsl:for-each select="$var1_instance_Payloads/syn:Payloads"> 
       <xsl:variable name="var2_Payloads" select="."/> 
      <xsl:for-each select="$var2_Payloads/ns1:response/ns0:query/ns0:row"> 
       <xsl:variable name="var2_row" select="."/> 
       <item> 
        <id> 
         <xsl:value-of select="number(string($var2_row/ns0:id))"/> 
        </id> 
        <name> 
         <xsl:value-of select="string($var2_row/ns0:name)"/> 
        </name> 
        <parts> 
         <xsl:for-each select="$var2_Payloads/ns0:query/ns0:row"> 
          <xsl:variable name="var4_row" select="."/> 
          <xsl:if test="string((number(string($var2_row/ns0:id)) = number(string($var4_row/ns0:id)))) != 'false'"> 
           <part> 
            <id> 
             <xsl:value-of select="number(string($var4_row/ns0:id))"/> 
            </id> 
            <name> 
             <xsl:value-of select="string($var4_row/ns0:part)"/> 
            </name> 
           </part> 
          </xsl:if> 
         </xsl:for-each> 
        </parts> 
       </item> 
      </xsl:for-each> 
      </xsl:for-each> 
     </items> 
    </xsl:template> 
</xsl:stylesheet> 

</localEntry> 

Die API-Antwort:

<items xmlns="http://ws.apache.org/ns/synapse" xmlns:syn="http://ws.apache.org/ns/synapse" xmlns:saxon="http://saxon.sf.net/" xmlns:exslt="http://exslt.org/common"> 
    <item> 
     <id>1</id> 
     <name>Item 1</name> 
     <parts> 
     <part> 
      <id>1</id> 
      <name>Part 1.1</name> 
     </part> 
     <part> 
      <id>1</id> 
      <name>Part 1.2</name> 
     </part> 
     <part> 
      <id>1</id> 
      <name>Part 1.3</name> 
     </part> 
     </parts> 
    </item> 
    <item> 
     <id>2</id> 
     <name>Item 2</name> 
     <parts> 
     <part> 
      <id>2</id> 
      <name>Part 2.1</name> 
     </part> 
     <part> 
      <id>2</id> 
      <name>Part 2.2</name> 
     </part> 
     </parts> 
    </item> 
</items> 
+0

Dies funktioniert perfekt! Danke für die ausführliche Antwort. Das erklärt alles, was mir fehlte. –

+0

froh zu hören, dass es für Sie arbeitet. Grüße. –