Can't retrieve xml element in mule through xpath3 - mule

Code to save the card number in the card number variable from request.
<set-variable variableName="cardNumber" value="#[xpath3('//#CardNumber', message.payload,'STRING')]" doc:name="Set cardNumber"/>
<logger level="INFO" message=" #[xpath3('//#CardNumber', message.payload, 'STRING')]" />
<logger message="#[flowVars['operationName']] cardNumber is = #[flowVars['cardNumberr']]" level="INFO" category="member" doc:name="Logger"/>
Below is the payload
mlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:typ="http://ws.loyalty.com/cpm/esb/amrp/2/1/member/types">
<soapenv:Header/>
<soapenv:Body>
<typ:GetMemberProfileRequest>
<typ:RequestContext Channel="WEB" Source="" Locale="" User="ONLINEUSER"/>
<typ:CardNumber>80000000021</typ:CardNumber>
</typ:GetMemberProfileRequest>
</soapenv:Body>
</soapenv:Envelope>
The card number is coming empty string in logs

#esha sherry, the xpath3 expression to get the card number should be
#[xpath3('/soapenv:Envelope/soapenv:Body/typ:GetMemberProfileRequest/typ:CardNumber', message.payload, 'STRING')]

Related

Issue with passing payload to another flow in munit

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

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 getting values from the payload

<flow name="datamappingFlow1" doc:name="datamappingFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="${hostname}" port="${port}" path="account" connector-ref="ConnectorWithoutMuleSession" doc:name="HTTP"/>
<jersey:resources doc:name="REST">
<component class="com.mycompany.qb.rest.AccountMappingService"/>
</jersey:resources>
<object-to-byte-array-transformer doc:name="Object to Byte Array"/>
<byte-array-to-object-transformer doc:name="Byte Array to Object"/>
<scatter-gather doc:name="upsert to db">
<flow-ref name="test1" doc:name="Flow Reference"></flow-ref>
<flow-ref name="test2" doc:name="Flow Reference"></flow-ref>
</scatter-gather>
</flow>
<flow name="test1" doc:name="test1">
<logger message="====Input deduction data is 1======#[payload]" level="INFO" doc:name="Logger"/>
<logger message="==== Input test1 data ======#[message.inboundProperties['City']]" level="INFO" doc:name="Logger"/>
<db:insert config-ref="Oracle_Configuration" doc:name="Database">
<db:parameterized-query><![CDATA[insert into test1(City)values(#[payload.City])]]></db:parameterized-query>
</db:insert>
</flow>
<flow name="test2" doc:name="test2">
<logger message="====Input deduction data is 2======#[payload]" level="INFO" doc:name="Logger"/>
<logger message="==== Input test2 data ======#[payload.City]" level="INFO" doc:name="Logger"/>
<db:insert config-ref="Oracle_Configuration" doc:name="Database">
<db:parameterized-query><![CDATA[insert into test2(City)values(#[payload.City])]]></db:parameterized-query>
</db:insert>
</flow>
Rest Component:
#Path("/")
public class AccountMappingService {
#POST
#Path("/mapping")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public String dataMapping(#Payload String content){
log.info("Rest Content is==>\n"+content);
return content;
}
Input data:
{
"City":"SFO1"
}
Output:
====Input deduction data is 2======{
"City":"SFO1"
}
==== Input test1 data ======null
====Input deduction data is 1======{
"City":"SFO1"
}
==== Input test2 data ======null
why I am getting null values here?
==== Input test1 data ======null
Comes from:
<logger message="==== Input test1 data ======#[message.inboundProperties['City']]" level="INFO" doc:name="Logger"/>
Inbound properties are set by the inbound endpoint. In your case, you're using an HTTP inbound endpoint. According to the doc:
To keep backward compatibility with previous versions of Mule, the headers and query parameters are also stored plain on the inbound properties.
So, unless you pass an HTTP header or query parameter named City in the HTTP request you send to your flow, the evaluation of #[message.inboundProperties['City']] can only return null.
The case of:
==== Input test2 data ======null
is different. It comes from:
<logger message="==== Input test2 data ======#[payload.City]" level="INFO" doc:name="Logger"/>
This calls .City on a payload of type String which can't work. I infer that the payload is of type String from:
public String dataMapping(#Payload String content)
You need to transform the JSON String payload into a java.util.Map if you want to extract values from it. From the doc you can see that you need to add a transformer:
<json:json-to-object-transformer returnClass="java.util.Map" />
USe Java map and then print them using a dot operation in logger, it will work.

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