Issue with passing payload to another flow in munit - mule

I am reading the JSON from the .txt file in MUnit test case, setting it to payload.I expect that payload has the field and its value defined in .txt file in form of map. However I am getting null instead of value.
Appreciate your help in isolating the issue.
<!-- TESTCASE: -->
<munit:test name="test-update" description="Validate calls to sub flows are being done properly ">
<munit:set payload="#[getResource('testData.txt').asStream()]" doc:name="Set Message">
<munit:inbound-properties>
<munit:inbound-property key="http.method" value="#['POST']" />
<munit:inbound-property key="http.request" value="#['/api/service/v1/update']" />
<munit:inbound-property key="http.request.path" value="#['/api/service/v1/update']" />
</munit:inbound-properties>
</munit:set>
<byte-array-to-object-transformer doc:name="Byte Array to Object" />
<logger level="INFO" message="Payload: #[payload]" doc:name="Logger"/>
<!-- Logs {"Id":"123"} which is read from testData.txt -->
<logger level="INFO" message="Id: #[payload.Id]" doc:name="Logger"/>
<!-- Logs "Id= null" instead of "Id: 123"-->
...
</munit:test>

Try to use:
<logger level="INFO" message="Id: #[payload.get('Id')]" doc:name="Logger"/>
Instead of:
<logger level="INFO" message="Id: #[payload.Id]" doc:name="Logger"/>

Related

"Redirecting into HTML page"

I have a flow where I am trying to load a HTML page if successfully login or fails. Flow is working but while doing POST job on browser side it's not redirecting to the loginSuccessful.html or login/loginFailure.html.
<flow name="GetLoginPage">
<http:listener config-ref="HTTP_Listener_Configuration" path="/login" allowedMethods="GET" doc:name="HTTP"/>
<parse-template location="login/index.html" doc:name="Parse Template"/>
</flow>
<flow name="Dologin">
<http:listener config-ref="HTTP_Listener_Configuration" path="/login" allowedMethods="POST" doc:name="HTTP"/>
<logger message="trying to login!!!!!!!!!!!" level="INFO" doc:name="Logger"/>
<choice doc:name="Choice">
<when expression="#[payload.username == "mule" and payload.password == "mule"]">
<logger message="login successfully!!!!!!!!!!!" level="INFO" doc:name="Logger"/>
<parse-template location="login/loginSuccessful.html" doc:name="Parse Template"/>
</when>
<otherwise>
<logger message="login failed!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" level="INFO" doc:name="Logger"/>
<parse-template location="login/loginFailure.html" doc:name="Parse Template"/>
</otherwise>
</choice>
</flow>
I took the liberty of creating my own payload in JSON and added the payload values from above:
{
"name": "mule",
"password": "mule"
}
Then, added a data transformer from JSON to Java, then I mildly adjusted your conditional test to eliminate the encoded quotes and replaced them with single quotes:
payload.username == 'mule' and payload.password == 'mule'
And the choice router correctly to pick up my test files with the parse template.

maxRedeliveryAttempts in Mule rollback exception strategy runs infinitely

I have a mule flow(mock-flow) that currently makes http calls to a couple of microservices. If one of the service calls fails due to a connection exception, i have a rollback exception strategy configured to reprocess the message (sending to kafka which in turn invokes the mock flow)but the retry seems to be happening indefinitely inspite of specifying a maxRedeliveryAttempts attribute. How do I limit the no of retries? Any help would be greatly appreciated
<flow name="mock-flow">
<logger level="INFO" message="CRD::: Calling Selldown settle Micro Service***"/>
<logger message="CRD::: Response received : #[message.payload]" level="INFO" />
<http:request config-ref="tp-ins-selldown-msConfig" path="/settle"
method="POST" doc:name="HTTP">
<http:success-status-code-validator
values="200,201" />
</http:request>
<http:request parseResponse="false" config-ref="tp-ins-limits-msConfig" path="booksdlimit"
method="POST" doc:name="HTTP">
<http:success-status-code-validator values="200,201"/>
</http:request>
<choice-exception-strategy doc:name="Choice Exception Strategy">
<rollback-exception-strategy when="exception.causedBy(java.net.ConnectException)" maxRedeliveryAttempts="2" doc:name="Rollback Exception Strategy">
<logger message="Will attempt redelivery" level="INFO" doc:name="Logger" />
<vm:outbound-endpoint exchange-pattern="one-way" path="kafka.inpath" doc:name="VM" />
<on-redelivery-attempts-exceeded>
<logger message="redelivery attempt exceeded" level="INFO" doc:name="Logger" />
<logger message="Retry exhausted" level="INFO" doc:name="Logger" />
</on-redelivery-attempts-exceeded>
</rollback-exception-strategy>
</choice-exception-strategy>
Since the maxReDeliveryAttempts attrtibute wasn't working(for whatever weird reason), I had to do it on my own(manually) by configuring a mule object store with the message request as the key and retry counter as the value.
<rollback-exception-strategy when="exception.causedBy(java.net.ConnectException)" doc:name="Rollback Exception Strategy">
<objectstore:retrieve config-ref="ObjectStore" key="#[uuid]" targetProperty="retryCounter" doc:name="Get value from ObjectStore" />
<logger level="INFO" doc:name="Logger" message="Retry counter --------------> #[retryCounter]"/>
<choice doc:name="Choice">
<when expression="#[retryCounter > 3]">
<logger message="Retry exhausted" level="INFO" doc:name="Logger" />
<objectstore:remove key="#[uuid]" config-ref="ObjectStore" ignoreNotExists="true" doc:name="Remove the key after retry exhaust" />
</when>
<otherwise>
<expression-component>
Thread.sleep(3000);
</expression-component>
<logger message="Will attempt redelivery" level="INFO" doc:name="Logger" />
<transformer ref="ObjectToString"/>
<vm:outbound-endpoint exchange-pattern="one-way" path="kafka.inpath" doc:name="VM" />
<objectstore:remove key="#[uuid]" config-ref="ObjectStore" ignoreNotExists="true" doc:name="Remove if exists" />
<objectstore:store config-ref="ObjectStore" key="#[uuid]" value-ref="#[retryCounter + 1]" doc:name="Store new value" />
</otherwise>
</choice>
</rollback-exception-strategy>
Seems even if maxRedeliveryAttempts variable had worked, it might not have helped my use case since when multiple requests are triggered, there is no way we would ensure that every request was retriggered only 3 times by simply relying on this attribute(unless mule internally uses a hashcode for every req to determine if it has already been retriggered or not)
Also flow variables and session variables didn't work in my case since the retrigger point was a kafka queue (which wasn't manually invoked by flow-ref). Hence had to use an object store

Mule Flow Reference Component throwing TransformerMessagingException while passing json

I have two flow one receive the xml payload and another json. I am routing the xml call to json flow using mule flow reference component after converting the xml to json payload. and second flow returns the json payload that i need to convert back to xml and reply to client.
My mule flow reference is throwing TransformerMsgException while receiving the json response from second flow.
Failed to transform from "json" to "java.lang.String" (org.mule.api.transformer.TransformerException). Message payload is of type: String
Here are the code for your reference -
<flow name="post:/chkdb:application/json:chkd-config">
<logger message="========json payload==>>>>==== #[message.payload]" level="INFO" doc:name="Logger"/>
<set-variable variableName="GGG_Number" value="#[json:ggg]" doc:name="Variable"/>
<!-- db call returns the payload-->
<choice doc:name="Choice">
<when expression="#[message.payload.size()>0]">
<set-payload value="{"indicator":"True"}" mimeType="application/json" doc:name="Set Payload"/>
</when>
<otherwise>
<set-payload value="{"indicator":"False"}" mimeType="application/json" doc:name="Set Payload"/>
</otherwise>
</choice>
<logger message="=========after producing json output=======" level="INFO" doc:name="Logger"/>
</flow>
<flow name="post:/chkdb:application/xml:chkdb-config">
<logger message="========= xml payload======== #[message.payload]" level="INFO" doc:name="Logger"/>
<json:xml-to-json-transformer mimeType="application/json" doc:name="XML to JSON"/>
<flow-ref name="post:/chkdb:application/json:chkdb-config" doc:name="post:/chkdb:application/json:chkdbapi-config"/> <!-- Getting exception here -->
<logger message=" after subflow call ==== #[message.payload]" level="INFO" doc:name="Logger"/>
<json:json-to-xml-transformer mimeType="application/xml" doc:name="JSON to XML"/>
<logger message="after json to xml conversion" level="INFO" doc:name="Logger"/>
</flow>
XML Request -
<ggg>DeJmp03bkqALlRFYmgu4+A==</ggg>
How i should retrieve the json response from other flow to current flow.
There is something missing here
First flow name: post:/chkdb:application/json:chkdbapi-config
Second flow name: post:/chkdb:application/xml:chkdbapi-config
Flow ref in second flow: post:/chkdb:application/json:chkdb-config
You are not referencing First flow.
So from your flow posted I can find few issues as follows :-
1. You are using where is the flow post:/chkdb:application/json:chkdb-config doesn't exits and it should be post:/chkdb:application/json:chkdbapi-config instead
2. Right now in the flow you are using <when expression="#[message.payload.size()>0]"> where as the message payload is in String format right now.
So, you can either use <when expression="#[message.payload.length()>0]">, using length() instead of size() or put a <json:json-to-object-transformer returnClass="java.lang.Object" doc:name="JSON to Object"/>before choice if you use #[message.payload.size()>0]
So the full code will be something as follows :-
<flow name="post:/chkdb:application/json:chkdbapi-config">
<logger message="========json payload==>>>>==== #[message.payload]" level="INFO" doc:name="Logger"/>
<!-- <json:json-to-object-transformer returnClass="java.lang.Object" doc:name="JSON to Object"/> --> <!-- incase you use #[message.payload.size()>0] in your choice -->
<!-- db call returns the payload-->
<set-variable variableName="GGG_Number" value="#[json:ggg]" doc:name="Variable"/>
<choice doc:name="Choice">
<when expression="#[message.payload.length()>0]">
<set-payload value="{"indicator":"True"}" mimeType="application/json" doc:name="Set Payload"/>
</when>
<otherwise>
<set-payload value="{"indicator":"False"}" mimeType="application/json" doc:name="Set Payload"/>
</otherwise>
</choice>
<logger message="=========after producing json output=======" level="INFO" doc:name="Logger"/>
</flow>
<flow name="post:/chkdb:application/xml:chkdbapi-config">
<logger message="========= xml payload======== #[message.payload]" level="INFO" doc:name="Logger"/>
<json:xml-to-json-transformer mimeType="application/json" doc:name="XML to JSON"/>
<flow-ref name="post:/chkdb:application/json:chkdbapi-config" doc:name="post:/chkdb:application/json:chkdbapi-config"/> <!-- Getting exception here -->
<logger message=" after subflow call ==== #[message.payload]" level="INFO" doc:name="Logger"/>
<json:json-to-xml-transformer mimeType="application/xml" doc:name="JSON to XML"/>
<logger message="after json to xml conversion" level="INFO" doc:name="Logger"/>
</flow>

Expected return type java.lang.Iterable

How to convert type=java.lang.String to type=java.lang.Iterable as batch step (Process Records) is expecting type of java.lang.Iterable. Note : Input is an xml file and mule flow is a batch job.
When the xml has only one 'Report_Entry' record below error is recieved. For multiple entries of 'Report_Entry' flow works fine.
<object-to-string-transformer doc:name="Object to String"/>
<logger message="#[payload]" level="INFO" doc:name="Logger"/>
<set-payload
value="#[xpath3('/*:Report_Data/*:Report_Entry', payload, 'NODESET')]" doc:name="Set Payload"/>
<logger message="XML Record - #[payload]" level="INFO" doc:name="Logger"/>
</batch:input>
<batch:process-records>
<batch:step name="Batch_Step1">
<json:object-to-json-transformer doc:name="Object to JSON"/>
<logger message="XML Record - #[payload]" level="INFO" doc:name="Logger"/>
<amqp:outbound-endpoint exchangeName="${amqp.exchangeName}" queueName="${amqp.queueName}" responseTimeout="10000" encoding="UTF-8" mimeType="application/xml" connector-ref="AMQP_Connector" doc:name="AMQP"/>
</batch:step>
</batch:process-records>
In the logger it is printing 'org.mule.api.processor.LoggerMessageProcessor: XML Record - net.sf.saxon.dom.DOMNodeList#57d263b4' after the set-payload condition. Our requirement is to convert the xml record to JSON and write to AMQP.
That's because of the splitter. If you just want a collection/iterable before the batch job, jsut use set-payload:
<set-payload
value="#[xpath3('/*:Report_Data/*:Report_Entry', payload, 'NODESET')]" />
<batch:execute name="test" />
This should wok regardless of the amount nodes.

Mule choice route depending on payload type ie object type?

I have route choice depending on the payload. The payload can be either list, map or string. The payload has to be identified and routed depending on the payload type.
I think that you want something like that
<choice doc:name="Choice">
<when expression="#[payload is List]">
<logger level="INFO" message="i am list" doc:name="Logger"/>
</when>
<when expression="#[payload is Map]">
<logger level="INFO" message="i am map" doc:name="Logger"/>
</when>
<when expression="#[payload is String]">
<logger level="INFO" message="i am string" doc:name="Logger"/>
</when>
<otherwise>
<logger message="class doesnt match with [list, map, string]" level="INFO" doc:name="Logger"/>
</otherwise>
</choice>
I do agree with EddĂș response, except for that I would add an otherwise path. If you don't do that and get something different than a list map or string you would get the rather cryptic error:
org.mule.api.routing.RoutePathNotFoundException: Can't process message because no route has been found matching any filter and no default route is defined. Failed to route event via endpoint: ChoiceRouter [flow-construct=testNull, started=true]. Message payload is of type: NullPayload