how to use for each in mule - mule

***I have a xml ---***
<DBOperation>
<ListOfOperation>
<operation>
<operationName>Insert</operationName>
<input>
<empid>3</empid>
<name>saurabh</name>
</input>
<operationName>Delete</operationName>
<input>
<empid>3</empid>
</input>
<operationName>insert</operationName>
<empid>3</empid>
<name>saurabh</name>
<operationName>update</operationName>
<input>
<empid>3</empid>
<name>raj</>
</input>
</operation>
</ListOfOperation>
</DBOperation>
I want to send this xml as a soap message but the entire operation at once such that using one request i can perform all the operations using choice routing....what is the most effecient method to do this in mulesoft...and if using for each what should be my collection tab configuration?

Do you need create a webservice that returns this xml as response?
If yes, This might help you:
JAVA (NO MULE)
Create a java bean and properties that match exactly with your xml : Response.java
Create a java class with one operation, that return this Response. And using some library, create your webservice:
#WebService
public class WebService {
public Response operation_name(Request request){
}
}
Request class if you need some parameter.
https://github.com/jrichardsz/java-web-services-template-soa-rest
Finally when you need return xml as response, use a unmarshall process to convert your xml file to Response.java.
http://www.javatpoint.com/jaxb-unmarshalling-example
MULE
I think are the same steps because Mule can create a web service from a java class:
https://docs.mulesoft.com/mule-user-guide/v/3.7/building-web-services-with-cxf
Regards

<flow name="dbopps">
<http:listener config-ref="HTTP_Listener_Configuration1" path="/" doc:name="HTTP"/>
***<foreach collection="#[xpath://.[xpath:local-name()='DBOperation']/*[xpath:local-name()='ListOfOperation']/*[xpath:local-name()='operation']]" doc:name="For Each" >***
<mulexml:dom-to-xml-transformer doc:name="DOM to XML"/>
<logger message="#[payload]" level="INFO" doc:name="Logger"/>
<set-variable variableName="name" value="#[xpath('//operationName').text]" doc:name="Variable"/>
<logger message="#[flowVars.name]" level="INFO" doc:name="Logger"/>
<choice tracking:enable-default-events="true" doc:name="Choice">
<when expression="#[flowVars.name == 'Insert']">
<db:insert config-ref="MySQL_Configuration" doc:name="Insert">
<db:parameterized-query><![CDATA[Insert into employees(empid,name) values ('43',#[xpath('//name').text])]]></db:parameterized-query>
</db:insert>
</when>
<when expression="#[flowVars.name == 'Delete']">
<db:delete config-ref="MySQL_Configuration" doc:name="Delete">
<db:parameterized-query><![CDATA[Delete from employees where empid='10']]></db:parameterized-query>
</db:delete>
</when>
</foreach>
<set-variable variableName="id" value="#[xpath://.[xpath:local-name()='DBOperation']/*[xpath:local-name()='ListOfOperation']/*[xpath:local-name()='operation']/*[xpath:local-name()='operationName']']" doc:name="Variable"/>
<set-payload value="<a> hello </a>" doc:name="Set Payload"/>
</flow>
This works fine for me you can check the collection tab configuration.

Related

Mule Munit with Choice followed by Dataweave transform

I have a flow that has a Choice followed by a Dataweave transform.
Input to the flow is json.
The choice has this when statement:
<when expression="#[payload.resultSet1.size() >= 1]">
The flow works well:
<flow name="test1">
<db:stored-procedure doc:name="MyStoredProc"></db:stored-procedure>
<choice doc:name="data found?">
<when expression="#[payload.resultSet1.size() >= 1]">
<dw:transform-message doc:name="CreateResponse">
<dw:set-payload resource="classpath:/dataweave/someDataweave.dwl" />
</dw:transform-message>
</when>
<otherwise>
<logger message="False: payload:#[payload]" level="INFO" doc:name="Log-False"/>
</otherwise>
</choice>
</flow>
Now I’m trying to create an Munit test for it. In order to get the choice to work, I had to do some playing with the data.
The choice now works but now the dataweave transform throws an exception because it says the json data is missing quotes.
The munit:
<munit:test name="test1-tryit" description="Test">
<mock:when messageProcessor=".*:.*" doc:name="Mock MyStoredProcResults">
<mock:with-attributes>
<mock:with-attribute name="doc:name" whereValue="#['MyStoredProc']"/>
</mock:with-attributes>
<mock:then-return payload="#[flowVars.jsonStoredProcResponse]" mimeType="text/json"/>
</mock:when>
<set-payload value="#[getResource('myTestData.json').asStream()]" doc:name="GetStoredProcResponse" mimeType="application/json"/>
<json:json-to-object-transformer returnClass="java.lang.Object" doc:name="JSON to Object"/>
<set-variable variableName="jsonStoredProcResponse" value="#[payload]" doc:name="jsonStoredProcResponse" />
<flow-ref name="test1" doc:name="Flow-ref to test1 flow" />
The data in myTestData.json file looks like this:
{"resultSet1": [{ "field1":"123" } ]}
Not sure how to resolve this issue and get both the choice and the transform to work.
Thanks.
Try using below groovy script:
<scripting: script name="mockDataBaseResponse" engine="groovy" doc:name="Script"><![CDATA[
Hashmap<String,String> cursor = new Hashmap<String,String>();
cursor.put("field1","123");
LinkedList List = new LinkedList();
List.add(cursor);
Hashmap<String,Object> cursorMap = new Hashmap<String,Object>();
cursorMap.put("resultSet1",List);
return cursorMap;]]>
</scripting:script>
Mock payload using script:
<mock:then-return payload="#[resultOfScript('mockDataBaseresponse')]" mimeType="text/java"/>
Also include this script file in you Munit xml file.

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>

JAXB with HTTP inbounds throws exception An invalid return type "class [B" was specified for transformer "JAXBMarshallerTransformer"

When I have XML payload from JMS inbound, XML to JAXB works as expected. But when I have same XML payload from HTTP inbound it throws an exception
An invalid return type "class [B" was specified for transformer "JAXBMarshallerTransformer" (org.mule.api.transformer.TransformerException)
Is it not a fair expectation from "XML to JAXB" component to have a XML payload from HTTP inbound? Please let me know what I am missing here.
Flow xml with with JMS and HTTP inbound. Only JMS inbound works as expected,
<flow name="productdemoFlow">
<jms:inbound-endpoint queue="my.test" connector-ref="Active_MQ" doc:name="JMS">
<jms:transaction action="NOT_SUPPORTED"/>
</jms:inbound-endpoint>
<logger message="#[payload]" level="INFO" doc:name="Logger"/>
<mulexml:jaxb-xml-to-object-transformer returnClass="com.chc.model.Product" jaxbContext-ref="JAXB_Context" doc:name="XML to JAXB Object"/>
<logger message="#[payload]" level="INFO" doc:name="Logger"/>
</flow>
<flow name="productdemoFlow1">
<http:listener config-ref="HTTP_Listener_Configuration" path="/test" allowedMethods="POST" doc:name="HTTP" />
<logger message="#["Payload ---------->" + payload.getClass().getName()]" level="INFO" doc:name="Logger"/>
<byte-array-to-string-transformer doc:name="Byte Array to String"/>
<logger message="#["Payload ---------->" + payload]" level="INFO" doc:name="Logger"/>
<mulexml:jaxb-xml-to-object-transformer encoding="windows-1252" mimeType="application/xml" jaxbContext-ref="JAXB_Context" doc:name="XML to JAXB Object"/>
</flow>
If I am not wrong, what you see is what you would expect.
The JMS inbound endpoint follows (by default, as in your case) a "one way" pattern, there is no response message to the client so there is no special requirement for the payload at the end of the flow.
The HTTP inbound endpoint follows (by default, as in your case) a "request-response" pattern so the payload, before sending the response to the client, should be of a type managed by the endpoint. In your case it is a java object instance of a not managed type, it must be converted to a correct type (String, InputStream, byte[], ...). For example:
<mulexml:jaxb-object-to-xml-transformer />

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 using XPath Evaluator

In the following mule flow I'm using xpath to decide which queue the message needs to be sent to. However the xpath expression is returning false, even though the XML has tc="121". Can you tell what am I doing wrong?
Below is the mule flow and XML evaluated by XPath.
Mule Flow :
<flow name="ProcessXMLRequest">
<jms:inbound-endpoint exchange-pattern="one-way" queue="mq.xml.request" />
<logger message="XML payload is #[payload]" level="INFO" />
<choice>
<when expression="/TXLife/TXLifeRequest/TransType/#tc='121'"
evaluator="xpath">
<jms:outbound-endpoint queue="mq.121.request.apps" />
</when>
<when
expression="/TXLife/TXLifeRequest/TransType/#tc='1122'"
evaluator="xpath">
<jms:outbound-endpoint queue="mq.1122.request.apps" />
</when>
<otherwise>
<jms:outbound-endpoint queue="mq.error"/>
</otherwise>
</choice>
</flow>
XML:
<TXLife xmlns:ns2="http://abc.com/services/mvi" xmlns="http://ACORD.org/Standards/Life/2">
<TXLifeRequest PrimaryObjectID="Holding_1">
<TransType tc="121">121</TransType>
<TransMode tc="2">2</TransMode>
</TXLifeRequest>
</TXLife>
This is a namespace issue: you need to configure the http://ACORD.org/Standards/Life/2 namespace and use it in your XPath expression.
In Mule, this is achieved with the namespace manager in such way:
<mulexml:namespace-manager>
<mulexml:namespace prefix="life2" uri="http://ACORD.org/Standards/Life/2"/>
</mulexml:namespace-manager>