Tuesday, July 21, 2015

How to get WSO2 ESB iterate mediator's iteration count

WSO2 ESB's iterate mediator is very useful to implement the Splitter Enterprise Integration Pattern.
It splits the message based on a given expression and process separately.

This sample shows how to get the iteration count.

Sample request

<symbols>
   <symbol>WSO2</symbol>
   <symbol>MSFT</symbol>
   <symbol>IBM</symbol>
   <symbol>ADBE</symbol>
   <symbol>AAPL</symbol>
   <symbol>ORCL</symbol>
   <symbol>RHT</symbol>
   <symbol>FB</symbol>
   <symbol>TWTR</symbol>
   <symbol>LNKD</symbol>
</symbols>

Sample proxy
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="count_iterate"
       transports="https,http"
       statistics="disable"
       trace="disable"
       startOnLoad="true">
   <target>
      <inSequence>
         <property name="it_count" value="0" scope="operation"/>
         <iterate expression="//symbols/symbol" sequential="true">
            <target>
               <sequence>
                  <property name="synapse_it_count" expression="get-property('operation', 'it_count')"/>
                  <script language="js">var cnt_str = mc.getProperty('synapse_it_count');
     var cnt = parseInt(cnt_str);
     cnt++;
     mc.setProperty('synapse_it_count', cnt.toString());</script>
                  <property name="it_count" expression="get-property('synapse_it_count')" scope="operation"/>
                  <aggregate>
                     <completeCondition>
                        <messageCount min="-1" max="-1"/>
                     </completeCondition>
                     <onComplete expression="//symbol">
                        <log level="custom">
                           <property name="number of symbols" expression="get-property('operation','it_count')"/>
                        </log>
                        <respond/>
                     </onComplete>
                  </aggregate>
               </sequence>
            </target>
         </iterate>
      </inSequence>
   </target>
   <description/>
</proxy>                               

Idea behind this sample is, using the 'operation' scope property[line 10]to increment the count in each iteration. The operation scope property cannot be read inside the script mediator (it supports only the synapse scope property) so introducing a synapse scope property[line 14] to be used inside the script mediator. After script mediator the value is assigned again to the operation scope property [line 19].
If we didn't use the operation scope property the value will not be remain in the next iteration. Also please note that the iterate mediator is in the sequential mode.

Getting the count like this method is useful when we have to map two different array based on its indexes. But please note if you want to only get the number of nodes in the message you can use the XPath function 'count' as follows

<property name="total_symbols" expression="count(//symbol)"/>


UPDATE on 28/09/2018:
The proxy can be simplified as follows by using the XPATH's number() function. Instead of using the script mediator to increment the count
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="count_iterate"
       startOnLoad="true"
       statistics="disable"
       trace="disable"
       transports="https,http">
   <target>
      <inSequence>
         <property name="it_count" scope="operation" value="0"/>
         <iterate expression="//symbols/symbol" sequential="true">
            <target>
               <sequence>
                  <property expression="number(get-property('operation','it_count') +1)"
                            name="it_count"
                            scope="operation"/>
                  <aggregate>
                     <completeCondition>
                        <messageCount max="-1" min="-1"/>
                     </completeCondition>
                     <onComplete expression="//symbol">
                        <log level="custom">
                           <property expression="get-property('operation','it_count')"
                                     name="number of symbols"/>
                        </log>
                        <respond/>
                     </onComplete>
                  </aggregate>
               </sequence>
            </target>
         </iterate>
      </inSequence>
   </target>
   <description/>
</proxy> 

To get rid of the decimal place in the result, we can use the string() and round() XPATH functions as follows

<property expression="string(round(get-property('operation','it_count')))" name="number of symbols"/>