Mule flowvars getting affected which preserves payload when the payload is changed - foreach

I am storing the output from DB in a flowvar #[flowvars.test] after which I am iterating the payload to remove few key, value pair. when the payload is modified inside the for loop the value which is stored in flowvars also getting modified.I am using mule 3.9 runtime.
<db:parameterized-query><![CDATA[select MachineName,TransactionId,SourceAPIName,Source,Target,ErrorCode,Severity,MailContent,ExceptionType,ExceptionMessage from Notification
where Notify='Y' and IsNotify='N']]>
</db:select>
</poll>
<expression-filter expression="#[payload.size()>0]" doc:name="Stop If No Records"/>
<set-variable variableName="test" value="#[message.payload]" doc:name="Variable"/>
<set-variable variableName="validatedEntries" value="#[[]]"
doc:name="ValidatedEntries" />
<logger level="INFO" doc:name="Logger"/>
<foreach collection="#[flowVars.test]" doc:name="For Each">
<logger level="INFO" doc:name="Logger"/>
<set-variable variableName="tempNotificationTable" value="#[payload.remove('TransactionID')]" doc:name="Temp NotificationTable"/>
<expression-component doc:name="Expression"><![CDATA[#[flowVars.validatedEntries.add(payload)]]]></expression-component>
</foreach>

For-Each will not create a deep copy of the object. Because of this, your original payload is getting changed.

Related

How to get only value part of linked list values from mule DB connector

I have the below flow which returns a list of values from DB with in mule.
I want to be able to get only the value part of the result from DB instead of a full linked list in the format of "column=value". I want to use the value part as part of a URL in the next http block. Please see my flow below. Any feedback will be helpful please.
<http:request-config name="HTTP_Request_Configuration" protocol="HTTPS" host="jsonplaceholder.typicode.com/#[flowVars.custID]" port="443" doc:name="HTTP Request Configuration"/>
<http:listener-config name="HTTP_Listener_Configuration1" host="0.0.0.0" port="8081" doc:name="HTTP Listener Configuration"/>
<flow name="dbcconnectorFlow">
<http:listener config-ref="HTTP_Listener_Configuration2" path="/lockStatus" allowedMethods="PUT" doc:name="HTTP"/>
<db:select config-ref="Oracle_Configuration" doc:name="Database">
<db:dynamic-query><![CDATA[select CUST_NO FROM CUSTOMERS WHERE LOCKED='N']]></db:dynamic-query>
</db:select>
<logger message="#[message.payload]"" level="INFO" doc:name="Logger"/>
<set-variable variableName="custID" value="#[message.payload[0]]" doc:name="Variable"/>
<http:request config-ref="HTTP_Request_Configuration" path="/" method="PUT" doc:name="HTTP"/>
</flow>
Ekow
One way to get only the value part of the result from DB is to put a transform message (Dataweave) component after the DB component and configure it as shown in this example:
<flow name="myprojectFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/" doc:name="HTTP"/>
<db:select config-ref="MySQL_Configuration" doc:name="Database">
<db:parameterized-query><![CDATA[select CompanyName from Customers limit 10]]></db:parameterized-query>
</db:select>
<response>
<dw:transform-message doc:name="Transform Message">
<dw:set-payload><![CDATA[%dw 1.0
%output application/json
---
payload.CompanyName[1]]]></dw:set-payload>
</dw:transform-message>
</response>
</flow>
The output is the first company name string in the array. The column name is not included.
Found a way around this. I had to convert the db results which was an object into xml using the object to xml transformer. Then use the splitter to split the results since I was expecting multiple output as below
[xpath3('//root/data/"xml_tag_of_required_data"', payload, 'NODESET')]. I then set the output as a variable and referenced the variable in the http endpoint URL.

Mule : Print Key and Value in ForEach

I want to print both key and value in ForEach. I am able to get the Keyset but not individual key.
<set-variable variableName="fileContents" value="#[message.payload]" />
<foreach collection="#[message.payload]">
<logger message="#[fileContents.keySet()]" level="INFO" doc:name="Logger"/>
<logger message="#[message:payload]" level="INFO" doc:name="Logger"/>
</foreach>
If fileContents is a Map, then you should use collections=#[payload.entrySet()]. That way within the foreach you can do #[payload.key] and #[payload.value] (because the payload in each step will be an Entry).

Mule-Throw error if the query parameter is not available

I need to throw an exception if the query parameter say "requestId" is not present in request URL.
The URL looks like this: my.server.com?requestId=123&age=26
Here I'm logging the requestId in message property like this:
<message-properties-transformer scope="session" doc:name="Adding requestId">
<add-message-property key="requestId" value="#[message.inboundProperties.'http.query.params'.requestId]"/>
</message-properties-transformer>
If the URL does not contain the requestId it will be null. But in this case I want to do a check for requestId whether it is present or not.
Then
As per your requirement you can do the following :-
<choice doc:name="Choice">
<when expression="#[org.mule.util.StringUtils.isNotEmpty(message.inboundProperties.'http.query.params'.requestId)]">
<logger message="query parameter exist" level="INFO" doc:name="Logger"/>
</when>
<otherwise>
<logger message="query parameter does not exist" level="INFO" doc:name="Logger"/>
<!-- Throw your exception here -->
<scripting:component doc:name="Script">
<scripting:script engine="Groovy"><![CDATA[
throw new IllegalArgumentException('query parameter does not exist')
]]></scripting:script>
</scripting:component>
</otherwise>
</choice>
Here If Query parameter exists it will simply log in a logger and if Query parameter does not exists it will throw the exception you want ..
Thanks all for putting your thoughts. Finally I got a simple way using groovy where I don't need to put any choice router or any expression filters. He is my code :
if(!message.getInboundProperty("http.query.params").find{ it.key == "requestId" }){
throw new IllegalArgumentException('requestId does not exist');
}
Have you tried message filters?
<message-filter throwOnUnaccepted="true">
<expression-filter
expression="#[message.inboundProperties.'http.query.params'.requestId != empty]" />
</message-filter>
This will throw an FilterUnacceptedException when requestId is null, false, empty, zero or an empty collection.
You have to change the condition if the filter needs to accept zero.
Use the below expression to check the query parameter availability in HTTP URL
#[org.mule.util.StringUtils.isNotEmpty(message.inboundProperties.'http.query.params'.requestId)]
See below sample code that used choice router and based on query param availability it routes the control
<choice doc:name="Choice">
<when expression="#[org.mule.util.StringUtils.isNotEmpty(message.inboundProperties.'http.query.params'.requestId)]">
<logger message="Query param available in request level="INFO" doc:name="Logger"/>
</when>
<otherwise>
<logger message="Query param not available in request level="INFO" doc:name="Logger"/>
</otherwise>
</choice>

How to use Stored Procedure with Mule 3.5 Batch Processing

I am using Mule 3.5 Anypoint connector and have moved from a select query to a stored procedures in the batch processing scope component. With that change mule does not like the object type that the stored procedure returns.
Here is the error that I get back:
ERROR 2014-06-26 15:15:00,426 [pool-15-thread-1] org.mule.exception.DefaultMessagingExceptionStrategy:
********************************************************************************
Message : Object "java.util.HashMap" not of correct type. It must be of type "{interface java.lang.Iterable,interface java.util.Iterator,interface org.mule.routing.MessageSequence,interface java.util.Collection}" (java.lang.IllegalArgumentException)
Code : MULE_ERROR--2
--------------------------------------------------------------------------------
The type of object returned from the database connector using a stored procedure is as such:
java.util.HashMap
With the Select statement (this works) the type is as such:
org.mule.util.CaseInsensitiveHashMap
Like stated above with the select statement this does work.
Some extra information about the system:
It is SQL Server 2008 R2
The database connector works fine with the stored procedure but errors when it reaches the process records section
<batch:job name="ons-esb-mainBatch1">
<batch:threading-profile poolExhaustedAction="WAIT"/>
<batch:input>
<poll doc:name="Poll">
<fixed-frequency-scheduler frequency="15" timeUnit="SECONDS"/>
<db:stored-procedure config-ref="Generic_Database_Configuration" doc:name="Database">
<db:parameterized-query><![CDATA[{ CALL otis.GetEntityQueueByTime() }]]></db:parameterized-query>
</db:stored-procedure>
</poll>
<logger level="INFO" doc:name="Logger"/>
</batch:input>
<batch:process-records>
<batch:step name="Batch_Step">
<choice doc:name="Choice">
<!-- Choice Selector Logic -- Taken Out to Save Space --!>
</choice>
</batch:step>
</batch:process-records>
<batch:on-complete>
<logger message="EntityQueues Completed Queueing into ActiveMQ" level="INFO" doc:name="Logger"/>
</batch:on-complete>
Summary
I would like to find a way to have the object be processed through the batch process will work as a select statement would.
A java.util.HashMap is not iterable. Try replacing the message payload with its entrySet():
<batch:input>
<poll doc:name="Poll">
<fixed-frequency-scheduler frequency="15" timeUnit="SECONDS"/>
<db:stored-procedure config-ref="Generic_Database_Configuration" doc:name="Database">
<db:parameterized-query><![CDATA[{ CALL otis.GetEntityQueueByTime() }]]></db:parameterized-query>
</db:stored-procedure>
</poll>
<set-payload value="#[message.payload.entrySet()]" />
<logger level="INFO" doc:name="Logger"/>
</batch:input>

Iterating an array using Mule's foreach scope

I would like to iterate through an array and use the value taken from the array to put it within an http inbound endpoint. How would I be able to iterate through this array and take the value from the array to place it as a variable within the http inbound endpoint?
The code that I used to try was:
<flow name="foreachFlow1" doc:name="foreachFlow1">
<poll frequency="2000">
<foreach collection="#[groovy:['localhost:8082', 'localhost:8083']]"
doc:name="For Each">
<http:outbound-endpoint exchange-pattern="request-response"
address="http://#[payload]" method="GET" doc:name="HTTP" />
</foreach>
</poll>
</flow>
and I get the error
Invalid content was found starting with element 'poll'
Inbound endpoints are message sources and can not be parametrized the way you're describing.
To achieve your goal, trying a <poll> message source to wrap a foreach that uses http:outbound-endpoint to perform GET (#method) request-response (#exchange-apttern) interactions.
The trick is to bring the results for the HTTP calls back through the foreach, which by default do not do it. The following illustrate a potential approach:
<flow name="foreachFlow1">
<poll frequency="2000">
<processor-chain>
<set-variable variableName="httpResponses" value="#[[]]" />
<foreach collection="#[groovy:['localhost:8082', 'localhost:8083']]">
<http:outbound-endpoint
exchange-pattern="request-response" address="http://#[payload]"
method="GET" />
<expression-component>httpResponses.add(message.payloadAs(java.lang.String))
</expression-component>
</foreach>
</processor-chain>
</poll>
<logger level="INFO" message="#[httpResponses]" />
</flow>
<!-- Test server stubs -->
<flow name="server8082">
<http:inbound-endpoint exchange-pattern="request-response"
address="http://localhost:8082" />
<set-payload value="This is 8082" />
</flow>
<flow name="server8083">
<http:inbound-endpoint exchange-pattern="request-response"
address="http://localhost:8083" />
<set-payload value="This is 8083" />
</flow>

Resources