2017-02-10 23 views
0

Я пытался выяснить, как заставить ESB WSO2 совершать звонки на два разных API и объединять их результаты в один отклик и работать без проблем. По своей сути, у меня есть два движки, которые я делаю запросы, которые отвечают что-то вроде этого:Объедините два запроса с использованием 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 'd хотел бы попросить обоих из них, а затем объединить их результаты, чтобы выглядеть примерно так:

<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> 

В принципе, каждый ответ от обоих API имеет список row s, каждый из которых содержит элемент id. id s в вызове /items являются уникальными в пределах этого ответа, и каждая строка в ответе от parts имеет номер id, который связывает его с строкой от /items.

Я получил следующее определение API в ESB:

<?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> 

inSequence здесь сильно упрощены, но это отправить два действительных запросов и получает обратно ожидаемые ответы. OutSequence, поскольку он написан здесь, никогда не отправляет ответ клиенту или не регистрирует ошибку на сервере. Если я удалю элемент correlateOn с aggregate, я вернусь к одному row, казалось бы, случайным образом, из одного из двух вызовов API. I думаюcorrelateOn - это то, что я хочу использовать здесь, но я не могу найти никакой полезной документации на нем из WSO2 или Apache, поэтому я уверен, что использую его неправильно. Мой фон XPath довольно слаб, поэтому я уверен, что выражение также может использовать некоторую работу.

Я, по крайней мере, на правильном пути здесь с клоном/агрегатным рисунком? Как мне совместить результаты этих двух запросов с чем-то похожим на мой пример? Если я смогу получить что-то вроде близкого расстояния, я смогу сделать все остальное с помощью XSLT.

ответ

4

посмотрите на этой демонстрации:

Backend 1 с элементами ответ:

<?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 с частями отклика:

<?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> 

Мой API вызова бэкенд 1 и бэкенд 2 и преобразование с 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> 

И мое преобразование XSLT:

<?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> 

Отклик API:

<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

Это отлично работает! Спасибо за подробный ответ; это объясняет все, что мне не хватало. –

+0

рад слышать, что он работает на вас. С уважением. –