Mule Munit with Choice followed by Dataweave transform - mule

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.

Related

how to use for each in 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.

validate fields in datamapper (CSV to JSON).

Converting from CSV to JSON using mule datamapper. I want to check if required field is empty. If empty log that field and discard it for further processing.
I know in script option we have if(input.data.length >0).'
But how to discard the whole row if this fails??
You can do this within mule datamapper simply by encapsulating the whole conversion within the if statements opening and closing braces. Something like this:
if ( input.Quantity > 0 ) {
output.id = input.id;
output.Customer = input.Customer;
output.Quantity = input.Quantity;
output.Price = input.Price;
}
However a different, perhaps better, approach would be to let the datamapper transform every row into JSON and then split and filter as seperate steps in the flow.
<flow name="filterindatamapperFlow2" doc:name="filterindatamapperFlow2">
<file:inbound-endpoint path="/tmp/inbox" doc:name="Inbound file"/>
<data-mapper:transform config-ref="CSV_To_UnfilteredJSON" doc:name="CSV To Unfiltered JSON"/>
<request-reply>
<vm:outbound-endpoint path="splittandprocess" exchange-pattern="one-way"/>
<vm:inbound-endpoint path="result"/>
</request-reply>
<json:object-to-json-transformer doc:name="Object to JSON"/>
<file:outbound-endpoint path="/tmp/outbox" doc:name="Outbound file"/>
</flow>
<flow name="splittandprocess">
<vm:inbound-endpoint path="splittandprocess" exchange-pattern="one-way"/>
<json:json-to-object-transformer returnClass="java.util.List" doc:name="JSON to Object"/>
<splitter expression="#[payload]" doc:name="Splitter"/>
<json:json-to-object-transformer returnClass="java.util.Map" doc:name="JSON to Object"/>
<message-filter doc:name="Filter Out Orders With No Quantity" onUnaccepted="handleFilteredMessages">
<expression-filter expression="#[payload['Quantity'] > 0]" />
</message-filter>
<collection-aggregator failOnTimeout="false" timeout="1000"/>
<vm:outbound-endpoint path="result" exchange-pattern="one-way"/>
</flow>
<flow name="handleFilteredMessages">
<logger message="Payload filtered #[payload]" level="ERROR" doc:name="Logger"/>
</flow>

Flow variable not working correct for DB select query

I am facing one Strange issue ... My Mule flow is as follow :-
<jdbc-ee:connector name="Database_Global" dataSource-ref="DB_Source" validateConnections="true" queryTimeout="-1" pollingFrequency="0" doc:name="Database">
<jdbc-ee:query key="InsertQuery" value="INSERT INTO getData(ID,NAME,AGE,DESIGNATION)VALUES(#[flowVars['id']],#[flowVars['name']],#[flowVars['age']],#[flowVars['designation']])"/>
<jdbc-ee:query key="RetriveQuery" value="Select * from getData where ID=#[flowVars['id']] "/>
</jdbc-ee:connector>
<flow name="MuleDbInsertFlow1" doc:name="MuleDbInsertFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8082" path="mainData" doc:name="HTTP"/>
<cxf:jaxws-service service="MainData" serviceClass="com.vertu.services.schema.maindata.v1.MainData" doc:name="SOAPWithHeader" />
<component class="com.vertu.services.schema.maindata.v1.Impl.MainDataImpl" doc:name="JavaMain_ServiceImpl"/>
<mulexml:object-to-xml-transformer doc:name="Object to XML"/>
<choice doc:name="Choice">
<when expression="#[message.inboundProperties['SOAPAction'] contains 'retrieveDataOperation']">
<processor-chain doc:name="Processor Chain">
<set-variable variableName="id" value="#[xpath('//id').text]" doc:name="Variable"/>
<logger message="ID from req #[flowVars['id']]" level="INFO" doc:name="Logger"/>
<jdbc-ee:outbound-endpoint exchange-pattern="request-response" queryKey="RetriveQuery" queryTimeout="-1" connector-ref="Database_Global" doc:name="Database (JDBC)"/>
<choice doc:name="Choice">
<when expression="#[message.payload.isEmpty()]">
<processor-chain>
<!-- Data not exists .. We cannot display -->
<logger message="No records found in Database !!!" level="INFO" doc:name="Logger"/>
</processor-chain>
</when>
<otherwise>
<processor-chain>
<!-- Data exists .. We cannotdisplay -->
<logger message="The Data retrieved from the Database" level="INFO" doc:name="Logger"/>
</processor-chain>
</otherwise>
</choice>
Now the issue is whenever I use the query RetriveQuery:- Select * from getData where ID=#[flowVars['id']]
It goes to the choice block where the logger shows No records found in Database !!! .. But you can see I placed a logger before call the SQL query by DB outbound
<logger message="ID from req #[flowVars['id']]" level="INFO" doc:name="Logger"/>
<jdbc-ee:outbound-endpoint exchange-pattern="request-response" queryKey="RetriveQuery" queryTimeout="-1" connector-ref="Database_Global" doc:name="Database (JDBC)"/>
which prints #[flowVars['id']] and I am successfully getting the value ..
But I don't know why it is going to the <when expression="#[message.payload.isEmpty()]">block ...
If I use the following in RetriveQuery : Select * from getData where ID=22
Then it's successfully getting the value of ID in the query ..
Please let me know why it's not getting the value in SQL query if I use a flowVars ..
It's executing successfully for insert and update query but not for Select ..
Pls note :- here the value of ID in Select * from getData where ID is integer ..
This is strange.
Try cleaning and re-building the project: the version that's running is maybe not using the latest config.
Yes, this was a strange and I found cleaning and re building the project in studio as David suggested worked .. may be there was an issue in picking up the latest config and reflecting in the proect

mule's http-proxy cannot be used in flow?

I would like to do a proxy for backend rest service, but before I forward the request to backend, I need to do some checks. I checked the docments, there is a http-proxy can be used to do the proxy, but when I put into the flow, there are exceptions. If I use the http:outbound-endpoint the method cannot be a dynamic MEL expression(rest method could be POST, GET, PUT, DELTE etc).
Could you give me a suggestion? An example will be better, Thanks a lot.
My Configuration:
<flow name="demo.routerFlow1" doc:name="demo.routerFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8080" doc:name="HTTP" />
<logger
message="Method: #[message.inboundProperties['http.method']], URI: #[message.inboundProperties['http.request.path']], Params: #[message.inboundProperties['http.query.params']]"
level="INFO" doc:name="Logger" />
<http:body-to-parameter-map-transformer doc:name="Body to Parameter Map" />
<choice doc:name="Choice">
<when expression="(payload['timestamp'] == null || payload['nonce'] == null)">
<expression-component doc:name="Check Required Params"><![CDATA[payload="{\"code\":\"PA001\", \"message\":\"missing required parameter timestamp and nonce\"}"]]>
</expression-component>
</when>
<otherwise>
<choice doc:name="Choice">
<when expression="!replayAttackCheck.validate(payload)" evaluator="groovy">
<expression-component doc:name="Check Required Params"><![CDATA[payload="{\"code\":\"PA002\", \"message\":\"timestamp or nonce is illegal\"}"]]>
</expression-component>
</when>
<otherwise>
<processor-chain doc:name="Processor Chain">
<pattern:http-proxy name="http-proxy-sample"> <!--line 38-->
<http:inbound-endpoint address="http://localhost:8080/"></http:inbound-endpoint>
<http:outbound-endpoint address="http://localhost:8081/"></http:outbound-endpoint>
</pattern:http-proxy>
</processor-chain>
</otherwise>
</choice>
</otherwise>
</choice>
</flow>
Error:
Caused by: org.xml.sax.SAXParseException; lineNumber: 38; columnNumber: 31; cvc-complex-type.2.4.b: The content of element 'processor-chain' is not complete. One of '{"http://www.mulesoft.org/schema/mule/core":annotations, "http://www.mulesoft.org/schema/mule/core":description, "http://www.mulesoft.org/schema/mule/core":abstract-message-processor, "http://www.mulesoft.org/schema/mule/core":abstract-outbound-endpoint, "http://www.mulesoft.org/schema/mule/core":abstract-mixed-content-message-processor}' is expected.
at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
Configuration patterns are standalone and separate from any flow and cannot be configured within one. They are predefined integration patterns for common scenarios. Flows are for rolling your own. See here: http://www.mulesoft.org/documentation/display/current/Choosing+Between+Flows+and+Patterns
As a side note: Your already listening on localhost:8080, so I think you just want a http:outbound-endpoint to the service your running on 8081
<http:outbound-endpoint address="http://localhost:8081/" />
You just need a http:outbound to the actual rest service in your otherwise block.
Try using the following.
<otherwise>
<http:outbound-endpoint address="http://localhost:8081/"></http:outbound-endpoint>
</otherwise>
Hope this helps.

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>