fb
WSO2 Enterprise Integrator 7 Minuten

Iteration und Aggregation mit Anrufvermittler im WSO2 ESB

Jenny Gligorovska
Jenny Gligorovska
Integration Consultant
Blog 7 1
Scrollen
Blog-7-1

Für mehrfache Anrufe oder die Simulation einer „for-each“ oder while-do“-Schleife können wir eine Kombination von zwei Mediatoren im WSO2 ESB verwenden: die iterierenden und aggregierenden Mediatoren.

Der iterierende Mediator kann eine Nachricht mit sich wiederholenden Elementen in mehrere Nachrichten aufteilen und in jeder Iteration Anrufe an einen Endpunkt tätigen.

Ein aggregierter Mediator sollte so eingestellt sein, dass er eine Mindestanzahl von gesendeten Nachrichten erhält, was der genauen Anzahl der Nachrichten entspricht, die in den Iterationsprozess gehen. Wir können einen Timeout als die Zeit angeben, wie lange der Aggregat-Mediator auf die Antworten warten soll. Wenn wir das Minimum und Maximum nicht angeben, wartet der Aggregator auf die Anzahl der iterierten Aufrufe. Diese Beispiele sind in WSO2 ESB Version 4.9.0 enthalten.

Blog-7-2
Abbildung 1 Grafische Darstellung des Iterations- und Aggregatflusses Nachricht anfordern
Banner-WSO2-Community-1-2

Nachricht anfordern

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v0="http://com/unisys/gem/uleaf/WSO2/v0">
   <soapenv:Header/>
   <soapenv:Body>
      <v0:WSO2Request>
         <MessageType>createAccounts</MessageType>
         <ParameterList>
            <Account>1</Account>
            <Account>2</Account>
            <Account>3</Account>
            <Account>4</Account>
         </ParameterList>
      </v0:WSO2Request>
   </soapenv:Body>
</soapenv:Envelope>

Sequenz mit Iterations- und Aggregat-Beispiel

<?xml version="1.0" encoding="UTF-8"?>
<sequence name="iterate-aggregate-example" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
  <property description="countRequests" expression="count(//Account)"
    name="countRequests" scope="default" type="STRING"/>
  <iterate expression="//Account" id="IterateAccountCreate"
sequential="true">
    <target>
      <sequence>
        <payloadFactory media-type="xml">
          <format>
            <echo:echoString xmlns:echo="http://echo.services.core.carbon.wso2.org">
              <in xmlns="">$1</in>
            </echo:echoString>
          </format>
          <args>
            <arg evaluator="xml" expression="//Account/text()"/>
          </args>
        </payloadFactory>
        <property action="remove" description="TRANSPORT_HEADERS"
          name="TRANSPORT_HEADERS" scope="axis2"/>
        <property description="OperationName" name="OperationName"
          scope="default" type="STRING" value="echoString"/>
        <header action="remove" name="To" scope="default"/>
        <header name="Action" scope="default" value="urn:echoString"/>
        <header name="SOAPAction" scope="transport" value="urn:echoString"/>
        <log category="DEBUG" description="***Request***">
          <property expression="$body" name="request"/>
        </log>
        <call>
          <endpoint key="echo"/>
        </call>
        <log category="DEBUG" description="***Response***" separator="***Response***">
          <property expression="$body" name="create_instanties_response"/>
        </log>
      </sequence>
    </target>
  </iterate>
  <aggregate description="" id="IterateAccountCreate">
    <completeCondition timeout="10">
      <messageCount max="{get-property('countRequests')}" min="{get
property('countRequests')}"/>
    </completeCondition>
    <onComplete expression="//ns:echoStringResponse" xmlns:ns="http://echo.services.core.carbon.wso2.org">
      <log description="***aggregated***" separator="***aggregated***">
        <property expression="$body" name="aggregated_body"/>      </log>
    </onComplete>
  </aggregate>
</sequence>

Antwortnachricht

<?php<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Body>
      <ns:echoStringResponse xmlns:ns="http://echo.services.core.carbon.wso2.org">
         <return>1</return>
      </ns:echoStringResponse>
      <ns:echoStringResponse xmlns:ns="http://echo.services.core.carbon.wso2.org">
         <return>2</return>
      </ns:echoStringResponse>
      <ns:echoStringResponse xmlns:ns="http://echo.services.core.carbon.wso2.org">
         <return>3</return>
      </ns:echoStringResponse>
      <ns:echoStringResponse xmlns:ns="http://echo.services.core.carbon.wso2.org">
         <return>4</return>
      </ns:echoStringResponse>
   </soapenv:Body>
</soapenv:Envelope>

Wichtige Hinweise für die Einstellung der iterativen und aggregierten Mediatoren

1.    Die Namen der Iterativen und Aggregierten Mediatoren sollten gleich sein

So weiß Aggregate, welche Anfragen warten und iterieren müssen, und Aggregate können in verschiedenen Sequenzen sein, z.B. Iterieren in der Eingabesequenz und Aggregat in der Ausgabesequenz.

id="IterateAccountCreate"

2.    Nicht blockierende Anrufe

Die Anrufe sollten nicht blockierend sein, wenn wir den Aggregat-Vermittler einsetzen, sonst findet die Aggregation nicht statt. Dies ist bei der Standardkonfiguration des ESB-Produkts Version 4.9 der Fall.

<call>
          <endpoint key="echo"/>
        </call>

3.    Aggregierter Ausdruck

Der aggregierte Ausdruck ist der Knotenpunkt der Antwort, an dem die Antworten bei der Aggregation gruppiert und in einem Körper zusammengefasst werden. Nach Abschluss der Aggregation gibt es einen Body mit mehreren Elementen des Knotens, der von diesem angegebenen onComplete  ausgewertet wird.

<onComplete expression="//ns:echoStringResponse" xmlns:ns="http://echo.services.core.carbon.wso2.org">

Verschachtelte Iterationen

Für die Transformationen der komplexen Nachrichten (Antworten) können wir verschachtelte Iterationen erstellen. In die erste Iteration können wir eine weitere Sequenz mit einem Iterations-Aggregat-Paar einfügen. So können wir mit den verschachtelten Payload oder den von beiden Iterationen zurückgegebenen Payload arbeiten.

Aggregierte verschachtelte Antworten

<aggregatedCategories>
      <category>
            <categoryNode1>value</categoryNode1>
            <categoryNode2>value</categoryNode2>
            <aggregatedSubcategories>
                  <subcategory>
                       <node1>value1</node1>
                       <node2>value2</node2>
                  </subcategory>
                  <subcategory>
                       <node1>value3</node1>
                       <node2>value4</node2>
                  </subcategory>
            </aggregatedSubcategories>
      </category>
      <category>
            <categoryNode1>value</categoryNode1>
            <categoryNode2>value</categoryNode2>
            <aggregatedSubcategories>
                  <subcategory>
                       <node1>value5</node1>
                       <node2>value6</node2>
                  </subcategory>
                  <subcategory>
                       <node1>value7</node1>
                       <node2>value8</node2>
                  </subcategory>
            </aggregatedSubcategories>
      </category>
</aggregatedCategories>

Eigentum innerhalb des Aggregat-Vermittlers im Einsatzbereich Operation

Wenn wir Aggregation in verschachtelter Weise verwenden, sollten wir eine Eigenschaft in das Aggregat setzen und sie dazu verwenden, die Payload im äußeren Aggregat-Vermittler zu kombinieren. Die Eigenschaft sollte sich im Bereich „Operation“ befinden.

<?php<aggregate id="IterateCategories">
    <completeCondition timeout="60">
      <messageCount max="-1" min="{get-property('countCategories')}"/>
    </completeCondition>
    <onComplete expression="//category">
      <property description="aggregatedCategories" expression="$body"
        name="aggregatedCategories" scope="operation" type="OM"/>
    </onComplete>
  </aggregate>

Sequenz mit verschachtelten Iterationen

Bei dieser Sequenz werden Kategorien in der ersten Iteration durchsucht, dann werden Unterkategorien in der zweiten verschachtelten Iterations-Aggregation durchsucht. Die äußere Aggregation enthält verschachtelte Antworten von aggregierten Kategorien und Unterkategorien innerhalb jeder Kategorie.

<?xml version="1.0" encoding="UTF-8"?>
<sequence name="categories-subcategories" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
  <call-template description="search-getCategories" target="search-getEntities">
    <with-param name="searchQuery" value="from ConversationCategory cc"/>
  </call-template>
  <property description="countCategories"
    expression="count(//ns18:Entity)" name="countCategories"
    scope="default" type="STRING" xmlns:ns18="http://organisation.com/entity"/>
  <iterate expression="//ns18:Entity" id="IterateCategories"
    sequential="true" xmlns:ns18="http://organisation.com/entity">
    <target>
      <sequence>
        <property description="currentCategory"
          expression="//ns18:Entity" name="currentCategory"
          scope="default" type="STRING" xmlns:ns18="http://organisation.com/entity />
        <property description="conversationSubCatNode"         expression="//ns18:AttributeValue[ns18:Name='conversationSubCat']"
          name="conversationSubCatNode" scope="default"
type="STRING" 	xmlns:ns18="http://organisation.com/entity"/>
        <switch source="get-property('conversationSubCatNode')!=''">
          <case regex="true">
            <enrich description="currentCategory">
              <source clone="true" property="currentCategory"
type="property"/>
              <target type="body"/>
            </enrich>
            <xslt description="gather-references-cat-SubCat"
              key="gov:custom/gatherReferences.xslt" source="$body">
              <property name="entity-field" value="ConversationCategory
conversationSubCat"/>
            </xslt>
            <call-template description="getSubcategories"
target="getEntities"/>
            <property description="ConversationSubCategories"
              expression="$body/ns18:GetEntitiesResponse"
              name="ConversationSubCategories" scope="default" type="STRING" xmlns:ns18="http://organisation.com/entity />
            <call-template description="iterate-subcategories" target="iterate-subcategories"/>
          </case>
          <default/>
        </switch>
        <payloadFactory description="category_subcategory" media-type="xml">
          <format>
            <category xmlns="">
                  $1
            <subcategories>$2</subcategories>
            </category>
          </format>
          <args>
            <arg evaluator="xml" expression="get-property('currentCategory')"/>
            <arg evaluator="xml" expression="get
property('operation','aggregatedSubcategories')"/>
          </args>
        </payloadFactory>
      </sequence>
    </target>
  </iterate>
  <aggregate id="IterateCategories">
    <completeCondition timeout="60">
      <messageCount max="-1" min="{get-property('countCategories')}"/>
    </completeCondition>
    <onComplete expression="//category">
      <property description="aggregatedCategories" expression="$body"
        name="aggregatedCategories" scope="operation" type="OM"/>
    </onComplete>
  </aggregate>
  <payloadFactory media-type="xml">
    <format>
      <categories xmlns="">$1</categories>
    </format>
    <args>
      <arg evaluator="xml" expression="get-property('operation','aggregatedCategories')"/>
    </args>
  </payloadFactory>
  <log description="***aggregatedCategories***"
separator="***aggregatedCategories***">
    <property expression="$body" name="BODY"/>
  </log>
  <xslt description="category-subcategory-type" key="gov:/my-project/xslt/category-subcategory-type.xslt"/>
  <log description="***TransformCategoriesResponse***" separator="***TransformCategoriesResponse***">
    <property expression="$body" name="BODY"/>
  </log>
</sequence>

Die Payload, die in der ersten (äußeren) Iteration aggregiert wird, ist benutzerdefiniert und enthält die aktuelle Kategorie und die aggregiertenUnterkategorien aus der zweiten (inneren) Iteration.

<payloadFactory description="category_subcategory" media-type="xml">
          <format>
            <category xmlns="">
                     $1
              <subcategories>$2</subcategories>
            </category>
          </format>
          <args>
            <arg evaluator="xml" expression="get
property('currentCategory')"/>
            <arg evaluator="xml" expression="get
property('operation','aggregatedSubcategories')"/>
          </args></payloadFactory>

Die zweite innere Iterationsgruppierung für die Unterkategorien befindet sich in einer gesonderten Vorlage, oder es kann auch eine Sequenz sein.

 <call-template description="iterate-subcategories" target="iterate-subcategories"/

Referenzen

https://docs.wso2.com/display/ESB490/Iterate+Mediator

https://docs.wso2.com/display/ESB490/Aggregate+Mediator

Wenn du Fragen zu diesem Blog hast, kontaktiere uns über den Kommentarbereich unten. Schau dir auch unsere WSO2-Tutorials, Webinare oder Whitepapers an, um weitere technische Informationen zu erhalten. Benötigst du Unterstützung? Wir bieten WSO2-Produktsupport, WSO2-Entwicklungsunterstützung, WSO2-Betriebsunterstützung und WSO2-Trainingsprogramme.