fb
Insights 7 minuten

Mediators itereren en aggregeren met call mediator in WSO2 ESB

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

Als we meerdere calls of simulaties hebben voor “for-each”- of “while-do”-loops, dan kunnen we in de WSO2 ESB een combinatie van twee mediatoren gebruiken: de iterate-mediator (voor herhalingen) en de aggregate-mediator (om te bundelen).

De iterate-mediator kan een bericht met herhalende elementen opsplitsen in meerdere berichten en kan bij iedere iteratie een call naar een eindpunt maken.

De aggregate-mediator dient ingesteld te worden op het minimaal aantal verzonden berichten dat ontvangen moet worden, wat precies overeen hoort te komen met het aantal berichten dat in de iterate gaat. We kunnen een timeout instellen om de maximale tijd te beperken die de aggregator mag wachten op de reacties. Als we geen minimale of maximale tijd opgeven, zal de aggregator wachten op het aantal geïtereerde calls. Deze voorbeelden doen we in WSO2 ESB versie 4.9.0.

Blog-7-2
Figuur 1 Grafische weergave van de iterate en aggregate flow
Banner-WSO2-Community-1-2

Aanvraagbericht

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

Een voorbeeldreeks die gebruikmaakt van iterate- en aggregate-mediatoren

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

Responsebericht

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

Belangrijke opmerkingen over het instellen van de iterate- en aggregate-mediatoren

1.      De namen van de iterate- en aggregate-mediatoren moeten hetzelfde zijn

Op deze manier weet de aggregate-mediator bij welke aanvragen er gewacht en geïtereerd of geaggregeerd moet worden. Dat kan in verschillende reeksen, bijvoorbeeld door te itereren in de inputreeks en te aggregeren in de outputreeks.

id="IterateAccountCreate"

2.      Non-blocking calls

De calls dienen non-blocking te zijn als we een aggregate-mediator gebruiken, omdat de aggregatie anders niet doorloopt. Dit is een standaardinstelling van het ESB-product in versie 4.9.

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

3.    Aggregate-uitdrukking

De aggregate-uitdrukking (aggregate expression) is het knooppunt van de response waarop de reacties gebundelend worden in een enkele set (of body). Nadat de aggregatie afgerond is, zal de set met meerdere elementen van het knooppunt geëvalueerd woorden door een speciale onComplete expression:

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

Geneste iteraties

Voor transformaties van complexe berichten (responses) kunnen we geneste iteraties gebruiken. Binnen de eerste iterate-mediator kunnen we nog een andere reeks met een iterate – aggregate paar zetten. Op die manier kunnen we aan de slag met geneste inhoud, of inhoud die teruggegeven is vanuit beide iteraties.

Geaggregeerde genested reacties

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

Eigenschappen binnen aggregate-mediators met als scope “operation”

Bij het gebruik van een geneste aggregate-mediator zullen we een eigenschap (property) in de aggregate moeten stoppen en deze eigenschap moeten gebruiken om de inhoud te combineren met de aggregate-mediator in de buitenste laag. Deze eigenschap dient vermeld te worden met als scope “operation”.

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

Reeks met geneste iteraties

Deze reeks zoekt categorieën in de eerste iteratie, daarna zoekt het naar subcategorieën in het tweede geneste iterate-aggregate paar. De buitenste aggregate zal de geneste reacties bevatten van de geaggregeerde categorieën en subcategorieën van iedere categorie.

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

De inhoud die geaggregeerd wordt in de eerste (buitenste) iteratie is op maat gemaakt en bevat de huidige categorie en de geaggregeerde subcategorieën van de tweede (binnenste) iteratie.

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

De tweede iterate-aggregate-laag voor de subcategorieën is in een afzonderlijk template, maar kan ook weer een reeks zijn.

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

Referenties

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

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

Als je vragen hebt over deze blogpost, neem dan gerust contact met ons op via de comments hieronder. Bekijk ook onze WSO2 tutorials, webinars of white papers voor meer technische informatie. Ondersteuning nodig? Wij bieden WSO2 Productondersteuning, en ondersteuning voor WSO2 Development, WSO2 Operational en WSO2 Trainingsprogramma’s.