Mule choice using XPath Evaluator - mule

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>

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.

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.

Mule-ESB: Mule filter based on HTTP Status

How do I use a filter other than a choice filter to call a subflow based on the http status?
<flow>
<http:outbound-endpoint exhange-pattern="request-response>
if http.status!=201
<flow-ref="subflow-to-invoke">
</flow>
Check this post Mule-esb: Process Jersey Response based on Status code using Choice Router?
Here is snippet from the above link, that answers your question.
<flow>
<http:outbound-endpoint address="${host}" exchange-pattern="request-response"/>
<choice>
<when expression="#[message.inboundProperties['http.status']]==201">
<flow-ref name=="flow2">
</when>
<when expression="#[message.inboundProperties['http.status']]==503">
<flow-ref name="flow3">
</when>
<when expression="#[payload instanceof java.lang.SocketException]">
<flow-ref name="flow4">
</when>
<otherwise>
<!-- decide what you want to do here -->
</otherwise>
</choice>
You don't have to use a filter for that but a choice message processor:
http://www.mulesoft.org/documentation/display/current/Choice+Flow+Control+Reference

Where in the application would you define the vm:endpoint for a dlqEndpoint-ref defined in an until-successful scope?

I'm trying to follow the example in this blog post (http://blogs.mulesoft.org/meet-until-successful-store-and-forward-for-mule/) for defining a dead letter queue for an until-successful scope element. This is the snippet from the blog post that doesn't quite make sense:
<vm:endpoint name="dlqChannel" path="dlq" />
<until-successful objectStore-ref="objectStore"
dlqEndpoint-ref="dlqChannel"
maxRetries="3"
secondsBetweenRetries="10">
...
</until-successful>
I don't quite understand where the vm endpoint lives in the app. I don't think it goes in the same flow as the until-successful element. I've tried putting it in its own flow but I get a NoSuchBeanDefinitionException.
Here is my relevant code:
<flow ....>
....
<until-successful objectStore-ref="objectStore" failureExpression="#[header:INBOUND:http.status != 201]" maxRetries="1" secondsBetweenRetries="5" doc:name="Until Successful" deadLetterQueue-ref="aggieFeedDestinedDeadLetterQueue">
....
</flow>
<flow name="edus-pubFlow1" doc:name="edus-pubFlow1">
<vm:inbound-endpoint exchange-pattern="one-way" path="aggieFeedDestinedDeadLetterQueue" doc:name="aggieFeedDestinedDeadLetterQueue"/>
<logger message="DEAD DEAD DEAD LETTER LETTER LETTER #[message]" level="INFO" doc:name="Logger"/>
</flow>
The dlqChannel attribute refers to a global endpoint. In your case, use:
<vm:inbound-endpoint exchange-pattern="one-way" path="aggieFeedDestinedDeadLetterQueue" />
<flow ....>
....
<until-successful objectStore-ref="objectStore"
failureExpression="#[header:INBOUND:http.status != 201]"
maxRetries="1" secondsBetweenRetries="5"
deadLetterQueue-ref="aggieFeedDestinedDeadLetterQueue">
....
</flow>
<flow name="edus-pubFlow1">
<endpoint ref="aggieFeedDestinedDeadLetterQueue" />
<logger message="DEAD DEAD DEAD LETTER LETTER LETTER #[message]" level="INFO" doc:name="Logger"/>
</flow>
Also if you're using Mule 3.3.0 or above, you can use MEL:
failureExpression="#[message.inboundProperties['http.status'] != 201]"

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.