Implement While and Do While Loops in MuleSoft 4.0

  • July 23, 2020

All programming languages, including C, C++ and Java, have loops like For, While and Do While to handle repeated operations n number of times based on a dataset. However, MuleSoft 4.0 only provides a For Each loop. A For Each loop on the dataset predefines time based on the number of records. In this blog, we’ll learn about While and Do While loop behavior in MuleSoft.

What are While and Do While loops?

While and Do While loops are like For loops such as iterate/repeat but aren’t on a dataset. However, they do have conditions:

  • In the ‘while’ loop, the controlling condition appears at the start of the loop
  • In the ‘do-while’ loop, the controlling condition appears at the end of the loop

While Loop

Do While Loop

Recursive function

A recursive function calls itself during its execution. This enables the function to repeat itself several times, outputting the result at the end of each iteration. An example of a recursive function is below. The recursive function must also contain a condition on which it will terminate the calling cycle or else it will run indefinitely and may cause out of memory issues.

Recursive Function

Implementing Do While Loop in Mule 4.0

We will impede the Do While loop using the recursive call:

  • Go to Project
  • Import the following XML as a new Mule Configuration File
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:ee="http://www.mulesoft.org/schema/mule/ee/core" xmlns:http="http://www.mulesoft.org/schema/mule/http"
	xmlns="http://www.mulesoft.org/schema/mule/core"
	xmlns:doc="http://www.mulesoft.org/schema/mule/documentation" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/ee/core http://www.mulesoft.org/schema/mule/ee/core/current/mule-ee.xsd">
	<http:request-config name="LocalHostService" doc:name="HTTP Request configuration" doc:id="81ce8454-039f-4dfa-9b5f-ec800fd69d64" >
		<http:request-connection protocol="HTTPS" host="localhost" />
	</http:request-config>
	<flow name="getAllData" doc:id="424a7f40-3912-400b-a06a-6c4e6e8dc109">
		<http:listener doc:name="Listener" doc:id="212465ea-f73f-4431-932e-b237651f3289" path="/getAllData" allowedMethods="GET" config-ref="HTTP_Listener_config"/>
		<flow-ref doc:name="mainFlow" doc:id="251d9282-69ac-4180-b425-54d091d24245" name="mainFlow" />
	</flow>
	<sub-flow name="mainFlow" doc:id="5a37075a-5af4-4030-af65-d6ac502a025f" >
		<ee:transform doc:name="init count" doc:id="ff54e8aa-b3cc-4be5-9569-9746eeb3174c">
			<ee:message>
			</ee:message>
			<ee:variables>
				<ee:set-variable variableName="count"><![CDATA[%dw 2.0
output application/java
---
0]]></ee:set-variable>
			</ee:variables>
		</ee:transform>
		<flow-ref doc:name="getPaginatedData" doc:id="c801ba2e-0164-46c5-8567-03f518399cb4" name="getPaginatedData" />
		<logger level="INFO" doc:name="Logger" doc:id="a64c8b87-f1f5-40be-88f2-e0030a893a9d" message="#[payload]"/>
		<ee:transform doc:name="payload" doc:id="9ccad799-d777-4484-9d88-4e79fb890226">
			<ee:message>
				<ee:set-payload><![CDATA[%dw 2.0
output text/plain
---
"Success"]]></ee:set-payload>
			</ee:message>
		</ee:transform>
	</sub-flow>
	<sub-flow name="getPaginatedData" doc:id="e00bdae1-e3c0-4d59-9e3a-f42277274264" >
		<http:request method="GET" doc:name="getDataByPageNumber" doc:id="4b7801a9-78e4-4027-b135-851ea07cc131" config-ref="LocalHostService" path="/getDataByPageNumber" targetValue="#[read(payload,'application/json')]">
			<http:query-params ><![CDATA[#[output application/java
---
{
	fromIndex: (vars.count * 200) + 1,
	toIndex: (vars.count + 1) * 200
}]]]></http:query-params>
		</http:request>
		<ee:transform doc:name="isDataPresent" doc:id="4e669d82-f07a-4d4d-ad93-c6127ab15506">
			<ee:message>
			</ee:message>
			<ee:variables>
				<ee:set-variable variableName="isDataPresent"><![CDATA[%dw 2.0
output application/java
---
isEmpty(payload..row)]]></ee:set-variable>
			</ee:variables>
		</ee:transform>
		<choice doc:name="Choice" doc:id="070e865e-72a1-46b8-b98e-58ae8f41b0d0" >
			<when expression="#[vars.isDataPresent == false]">
				<ee:transform doc:name="updateCount and accPayload" doc:id="873dd36c-2f56-48d3-86f7-f7be2ea92b78" >
					<ee:message >
					</ee:message>
					<ee:variables >
						<ee:set-variable variableName="count" ><![CDATA[%dw 2.0
output application/java
---
vars.count + 1]]></ee:set-variable>
						<ee:set-variable variableName="accPayload" ><![CDATA[%dw 2.0
output application/json
---
if (isEmpty(vars.accPayload))
	payload.response.result.Candidates.row
else
	vars.accPayload ++ payload.response.result.Candidates.row]]></ee:set-variable>
					</ee:variables>
				</ee:transform>
				<flow-ref doc:name="getPaginatedData" doc:id="faac116f-ab7f-4897-b69d-584d242049cd" name="getPaginatedData"/>
			</when>
			<otherwise >
				<ee:transform doc:name="payload" doc:id="17aaa9c5-881b-4622-ada2-dd8557985ca6">
					<ee:message>
						<ee:set-payload><![CDATA[%dw 2.0
output application/json
---
if (isEmpty(vars.accPayload))
	[]
else
	vars.accPayload]]></ee:set-payload>
					</ee:message>
				</ee:transform>
				<logger level="INFO" doc:name="Logger" doc:id="78b6b7ed-ebac-4539-8fdd-60d6182573a3" message="#['data not found after iteration: ' ++ (vars.count default &quot;&quot;)]"/>
			</otherwise>
		</choice>
	</sub-flow>
</mule>

Get All Data Flow — this Flow calls the main Flow

Get All Data Flow

Main Flow — this Flow initiates pageNumber (count) variable and calls the getPaginatedData flow

Main Flow

Get Paginated Data Flow — this flow “getDataByPageNumber” checks to see if data is present, accumulates the output and calls the getPaginatedData Flow in case “getDataByPageNumber” max accepted record; otherwise, it will terminate the Flow and return all data to Main Flow

Get Paginated Data Flow

To implement the same in your project, replace “getDataByPageNumber” with your service call; update “isDataPresent,” “updateCount” and “accPayload” based on your requirements

Limitation of this approach

MuleSoft restricts the nested call depth to a default value of 25 — if the nested call depth reaches beyond 25, MuleSoft throws the following exception:

Message: Too many child contexts nested

Error type: MULE:CRITICAL

To overcome this issue, set org.mule.runtime.core.privileged.event.BaseEventContext.maxDepth higher than 25 and based on your requirements.

As we accumulate all the data, it may cause memory issues. Keep this in mind while using this approach.

Scenarios where this can be implemented

This approach can be used when you don’t know how many records you need to fetch and when some looping isn’t achievable using for each loop.

— By Mohammad Mazhar Ansari