Return individual values from linkedHashMap in Mule - mule

I have an output from a webservice in Mule that returns a linkedHashMap and I need to get the individual values to be dynamically inserted into a template. The template is used to send email through the SMTP connector. I can get all values using MEL #[payload], but I can't get them one by one. I've tried #[payload.get(0)], #[payload[0]] but they all return null.
The Mule XML looks like this:
<flow name="MW_Flow">
<file:inbound-endpoint path="C:\....\1" connector- ref="File" responseTimeout="10000" doc:name="File" pollingFrequency="60000"/>
<ws:consumer config-ref="File_Read_WS" operation="all3" doc:name="FileRead DBWriter WS"/>
<dw:transform-message metadata:id="6ee92ba8-9f67-40d6-bfa3-3e237da20822" doc:name="Transform Message">
<foreach doc:name="For Each">
<logger message="#[payload]" level="INFO" doc:name="Logger"/>
<parse-template location="C:\.....\Templates\Mail.txt" metadata:id="b7d894eb-465b-47f7-a542-b49fc4fb53d9" doc:name="Parse Template"/>
<logger message="2: #[message.exception] #[message.dataType] #[payload]" level="INFO" doc:name="Logger"/>
</foreach>
</flow>
The template (plain text file) looks a bit like this:
Hello [name].
This is email from [name2]. The following event [event].....
All I get are null values except when using #[payload] which returns the whole row (4 values).
Any help greatly appreciated!
/Johan

If your payload is a Map then payload.get(0) or payload[0] will behave as if you are trying to get a value from map with 0 as key, which I guess doesn't exist in your map.
Try accessing it with name - #[payload.name] or #[payload.name2] or #[payload[name]]

Related

how to insert multiple rows in mule database connector?

I want to insert multiple rows in mule database connector at a time. Could anyone kindly please help me on this?.
I can successfully insert the below message as a post request to a mule flow.
{
"patient_todo_id" : "2",
"comment_date" : "2017-09-20 14:41:16",
"comment_text" : "send me the steps to check the Pulse rate"
}
How to insert the below post message into a database in a mule flow?
[{
"patient_todo_id" : "2",
"comment_date" : "2017-09-20 14:41:16",
"comment_text" : "send me the steps to check the Pulse rate"
},
{
"patient_todo_id" : "2",
"comment_date" : "2017-09-20 14:41:16",
"comment_text" : "send me the steps to check the Pulse rate"
}]
Please find the below mule flow configuration file which has been configured to insert a single row at a time.
<flow name="carrotcube-patient-todo-commentFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="${http.path.mrs.todo.comment}" doc:name="HTTP"/>
<set-variable variableName="variable" value="#[payload]" mimeType="application/json" doc:name="Variable"/>
<json:json-to-object-transformer returnClass="java.lang.Object" doc:name="JSON to Object"/>
<logger message="#[payload.comment_text]" level="INFO" doc:name="Logger"/>
<db:insert config-ref="MySQL_Configuration" doc:name="Database">
<db:parameterized-query><![CDATA[insert into patient_todo_detail(patient_todo_id,comment_date,comment_text) values (#[payload.patient_todo_id],#[payload.comment_date],#[payload.comment_text])]]></db:parameterized-query>
</db:insert>
</flow>
Use the Bulk update mode and pass your connector a collection of object to insert. In Studio, simply check "Bulk mode" in the Basic Settings section of the database connector. The example array you provide in your question is just fine, you can then do something like:
<db:insert config-ref="MySQL_Configuration" bulkMode="true" doc:name="Database">
<db:parameterized-query><![CDATA[
INSERT INTO mytable(id, name)
VALUES (#[payload.id], #[payload.name]);]]>
</db:parameterized-query>
</db:insert>
Each element of your list will then become the payload in the connector and will be inserted. You do not need to use a for-each or any loop mechanism. Make sure to pass an iterable object though.
See the related docs:
https://docs.mulesoft.com/mule-user-guide/v/3.8/database-connector#setting-up-database-connector-operation
This is super easy, you can do it by 2 ways:
solution1 using splitter:
<flow name="testFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/test" doc:name="HTTP"/>
<json:json-to-object-transformer returnClass="java.lang.Object" doc:name="JSON to Object"/>
<collection-splitter doc:name="Collection Splitter"/>
<logger message="insert into patient_todo_detail(patient_todo_id,comment_date,comment_text) values (#[payload.patient_todo_id],#[payload.comment_date],#[payload.comment_text])" level="INFO" doc:name="Logger"/>
<collection-aggregator failOnTimeout="true" doc:name="Collection Aggregator"/>
<json:object-to-json-transformer doc:name="Object to JSON"/>
</flow>
solution2 using foreach:
<flow name="testFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/test" doc:name="HTTP"/>
<json:json-to-object-transformer returnClass="java.lang.Object" doc:name="JSON to Object"/>
<foreach doc:name="For Each" collection="#[payload]">
<logger message="insert into patient_todo_detail(patient_todo_id,comment_date,comment_text) values (#[payload.patient_todo_id],#[payload.comment_date],#[payload.comment_text])" level="INFO" doc:name="Logger"/>
</foreach>
<json:object-to-json-transformer doc:name="Object to JSON"/>
</flow>
In both the cases, you can see your logger is getting the correct values in your SQL statement you are using :
<logger message="insert into patient_todo_detail(patient_todo_id,comment_date,comment_text) values (#[payload.patient_todo_id],#[payload.comment_date],#[payload.comment_text])" level="INFO" doc:name="Logger"/>
Now you can replace the logger with your DB component
UPDATE based on the comment:
<set-variable variableName="myMap" value="#[new java.util.HashMap()]" doc:name="Variable"/>
<foreach doc:name="For Each" collection="#[payload]">
<db:insert config-ref="MySQL_Configuration" doc:name="Database">
<db:parameterized-query><![CDATA[insert into patient_todo_detail(patient_todo_id,comment_date,comment_text) values (#[payload.patient_todo_id],#[payload.comment_date],#[payload.comment_text])]]></db:parameterized-query>
</db:insert>
<expression-component doc:name="Expression"><![CDATA[flowVars.myMap.put('row'+flowVars.counter,payload)]]></expression-component>
</foreach>
<logger message="Final status #[flowVars.myMap.toString()]" level="INFO" doc:name="Logger"/>
Here at the end you will get in logger the status of each row inserted which is 1 means successful
To get a particular row details ouside foreach:
<logger message="#[flowVars.myMap.get('row1').toString()]" level="INFO" doc:name="Logger"/>
So, based on the status you can further display your custom status messages
Ashok, I just crossed this hurdle, so you got really lucky here as I had to struggle through this for a while. Very surprising that such a common scenario was not to be found on the Internet. The steps are listed below ,and the flow is below too.
1) Use transform to convert the post payload to java list (application/java) – the output should just have payload (remove the curly braces and just put payload). This payload should come from the body.
2) Use for each scope and put the database insert statement there
3) In the database insert statement use [payload[‘username’]] kind of syntax to refer to the value of username in the current record (or whatever field names you have). I am using a stored prod to insert, but you get the idea.
I am not able to post the flow here .. it's cutting it off and showing it weird. I'll try to send you through email if you can share.
Now all I have to figure out is how to send a nice message back with the insert status. Anybody who already has done that.. appreciate your inputs!
Ashok, replying to your comment on aggregating the response from the for each here, as I can't add comments yet. Check out the following link, which offer s a few options.
https://forums.mulesoft.com/questions/60273/save-of-for-each-database-query-response-to-a-new.html

synchronizing a database insert and select behind a web service

I'm struggling to figure out how to solve this problem in mule using the studio and thought that perhaps reaching out to the good users of SO may be of some help.
I have a simple webservice that takes a request from a client. this request will preform an insert into a database table, effectively using this database as a message queue. A separate process periodically polls this table, performs additional processing on the message, and then writes results to an output table. the database insert and subsequent select will be linked by a a correlationId that I can pass along to ensure I get the result for the message that was sent. Unfortunately, the software this will integrate with requires this pattern to work correctly.
Here's the workflow that is needed:
HttpRequest -> insert record into a table -> wait(or poll/retry/etc?) until a record is written to another table by a separate process(with the same correlationId) -> return data from this other table back to the httpRequest
here's a sample flow that is as close as i've been able to get with this. Oddly enough, this flow does actually return a payload, however it seems to always be "1". i can't quite see how to make this flow retry the database query until a row exists and then return the resulting row.
How should i be synchronizing 2 database calls? is this possible within mule perhaps with a different combination of components?
Thanks.
<flow name="mainFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="hello" doc:name="HTTP"/>
<cxf:jaxws-service doc:name="CXF" configuration-ref="CXF_Configuration" serviceClass="kansas.MuleTestServiceImpl"/>
<db:insert config-ref="Oracle_Configuration" doc:name="Database">
<db:parameterized-query><![CDATA[insert into tblRequest (id, correlationId) values(#[payload], #[message.correlationId])]]></db:parameterized-query>
</db:insert>
<until-successful objectStore-ref="MyObjectStore" maxRetries="5" millisBetweenRetries="2000" doc:name="Until Successful" > <!-- failureExpression="???" -->
<db:select config-ref="Oracle_Configuration" doc:name="Database">
<db:parameterized-query><![CDATA[select correlationId,msgResponse from tblResponse where correlationId = #[message.correlationId]]]></db:parameterized-query>
</db:select>
</until-successful>
<logger level="INFO" doc:name="Logger" message="#[payload]"/> <!-- why is payload always = 1? -->
</flow>
Mule is great tool but it makes your life too easy. Sometime so easy that you forget simple things.
In your case you forgot that payload is one object which is result of last component. Think about flow as rails with just one cart. Whatever you load on last station is delivered to the next one. And then process repeats. What was originally delivered to the station does not matter. Matters what you load.
In your case first database component has original payload from CXF and stores something in the database. It returns result of the INSERT statement which is 1 - one row is inserted. So our payload keeps deliver new cargo - 1.
But you need original payload from CXF. Where it is? It is gone - we have only one flow, one pair of trails, one cart.
What to do in this situation? Keep required information not in the cart but somewhere else. For example in flow variables. Store original payload in some variable and then restore it when it required again. Like this
<flow name="mainFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="hello" doc:name="HTTP"/>
<cxf:jaxws-service doc:name="CXF" configuration-ref="CXF_Configuration" serviceClass="kansas.MuleTestServiceImpl"/>
<set-variable variableName="storedPaylod" value="#[payload]" doc:name="Store original payload"/>
<db:insert config-ref="Oracle_Configuration" doc:name="Database">
<db:parameterized-query><![CDATA[insert into tblRequest (id, correlationId) values(#[payload], #[message.correlationId])]]></db:parameterized-query>
</db:insert>
<set-payload value="#[flowVars.storedPaylod]" doc:name="Restore Payload"/>
<until-successful objectStore-ref="MyObjectStore" maxRetries="5" millisBetweenRetries="2000" doc:name="Until Successful" > <!-- failureExpression="???" -->
<db:select config-ref="Oracle_Configuration" doc:name="Database">
<db:parameterized-query><![CDATA[select correlationId,msgResponse from tblResponse where correlationId = #[message.correlationId]]]></db:parameterized-query>
</db:select>
</until-successful>
<logger level="INFO" doc:name="Logger" message="#[payload]"/> <!-- why is payload always = 1? -->
</flow>
Good idea will be to check that first database component really returns 1 - record is inserted. Do this, produce alerts on the error, and then restore original payload and continue your flow.
The best solution to avoid killing the actual value of your payload after the database insert is to make use of the Message Enricher processor.
try this code below:
<flow name="mainFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="hello" doc:name="HTTP"/>
<cxf:jaxws-service configuration-ref="CXF_Configuration" serviceClass="kansas.MuleTestServiceImpl" doc:name="CXF"/>
<enricher source="#[payload]" target="#[flowVars.insertResponse]" doc:name="Message Enricher">
<db:insert config-ref="Oracle_Configuration" doc:name="Database">
<db:parameterized-query><![CDATA[insert into tblRequest (id, correlationId) values(#[payload], #[message.correlationId])]]></db:parameterized-query>
</db:insert>
</enricher>
<flow-ref name="dbSelectSubFlow" doc:name="dbSelectSubFlow"/>
<logger message="#[payload]" level="INFO" doc:name="Logger"/>
</flow>
<sub-flow name="dbSelectSubFlow">
<until-successful objectStore-ref="MyObjectStore" maxRetries="5" millisBetweenRetries="2000" doc:name="Until Successful">
<db:select config-ref="Oracle_Configuration" doc:name="Database">
<db:parameterized-query><![CDATA[select correlationId,msgResponse from tblResponse where correlationId = #[message.correlationId]]]></db:parameterized-query>
</db:select>
</until-successful>
</sub-flow>

Facing error in Batch Processing mule esb

I am facing problem in batch processing mule esb. If I set any payload in process record face and try to get that payload in oncomplete face then not getting that payload. same problem with variable and property.
If I set any property in process record phase and try to get in on complete phase then always get null value.
how to get those value in oncomplete phase?
below is flow..
<batch:job name="TestBatch" max-failed-records="-1">
<batch:input>
<component class="com.test.RecordTest"
doc:name="Java" />
<json:object-to-json-transformer
doc:name="Object to JSON" />
<custom-transformer class="com.test.CustomTr"
doc:name="Java" />
</batch:input>
<batch:process-records>
<batch:step name="Batch_Step1" accept-policy="ALL">
<batch:commit size="5" doc:name="Batch Commit">
<!-- Insert record in Salesforce -->
</batch:commit>
</batch:step>
<batch:step name="Batch_Step2" accept-policy="ONLY_FAILURES">
<logger message="STEPP #[getStepExceptions()]" level="INFO" doc:name="Logger"/>
<set-property propertyName="error" value="STEPP #[getStepExceptions()]" doc:name="Property"/>
<set-payload value="#[getStepExceptions()]" doc:name="Set Payload"/>
</batch:step>
</batch:process-records>
<batch:on-complete>
<logger level="INFO" doc:name="Logger" message="--> #[payload.failedRecords] --> #[message.payload] "/>
<logger message="error--- #[message.outboundProperties['error']] " level="INFO" doc:name="Logger"/>
</batch:on-complete>
</batch:job>
I got null in property logger
How can I solve this?
I got some bad news from you :-).
Batch processing by design will not old any of the value you may try to set in steps, especially payload.
When I started working with it I was also expecting to have session variable on complete phase in a correct status but this is not the case, they are completely wiped at each step.
Now I don't think this is a bug, but it is really a design feature that I can understend even if I don't really love it.
I solved the same problem by using the object store connector.
It will allow you to access the mule Object Store API via nice XML configuration block, in this way you can store in memory variables that you can recover after in your on-complete without them being affected by flow logic.
Hope this helps

Mule ESB - Get payload value

I'm not able to get the ID from the query result.
Mule version is 3.5.
This is the flow:
<flow name="mule.activity">
<poll doc:name="Poll">
<fixed-frequency-scheduler frequency="10000"/>
<db:select config-ref="JSDB" doc:name="Database">
<db:parameterized-query><![CDATA[SELECT ID FROM ACTIVITY where rownum = 1]]></db:parameterized-query>
</db:select>
</poll>
<logger message="Current payload is #[payload]" level="DEBUG" category="mule.activity" doc:name="Logger"/>
<logger message="Current payload size is #[payload.size()]" level="DEBUG" category="mule.activity" doc:name="Logger"/>
<logger message="Current id is #[payload.ID]" level="DEBUG" category="mule.activity" doc:name="Logger"/>
</flow>
And this is the log
[2015-03-18 13:13:36,875] DEBUG: Current payload is [{ID=1363230}]
[2015-03-18 13:13:36,881] DEBUG: Current payload size is 1
[2015-03-18 13:13:36,888] DEBUG: id is null
Any help will be greatly appreciated.
The returning payload of a query with the DB connector is always a list, whether is 0,1, or n elements.
Your MEL expression is assuming it's a map: #[payload.ID]
You should do something like #[payload.get(0).ID]
Then again I would advice you no to use this form to accessing maps
[payload.get(0).ID]
But rather
[payload.get(0)['ID']]
In the first example if you make a mistake with the id of the map you're trying to access the error isn't always that descriptive.
HTH

Mule foreach : Splitter returned no results

I get a list of files on amazon S3 and iterate over the list of files and process one file at a time. The corresponding flow is as follows --
<flow name="process-from-s3" doc:name="process-from-s3"
processingStrategy="synchronous">
<poll doc:name="Poll" frequency="${s3-poll-interval}">
<s3:list-objects config-ref="Amazon_S3" doc:name="Get List of files"
accessKey="${s3-access-key}" secretKey="${s3-secret-key}"
bucketName="${s3-read-bucket}" />
</poll>
<choice doc:name="Choice">
<foreach doc:name="For Each">
<set-session-variable variableName="s3_file_name" value="#[payload.getKey()]" doc:name="Session Variable"/>
<logger message="From bucket ( ${s3-read-bucket} ), received the file #[s3_file_name]" level="INFO" doc:name="Logger"/>
<flow-ref name="process_s3_file" doc:name="Flow Reference"/>
</foreach>
</choice>
</flow>
The flow works well, however it keeps on spitting the following log statements if there are no files found.
[03-06 21:52:05] WARN Foreach$CollectionMapSplitter
[[myapp].connector.polling.mule.default.receiver.01]: Splitter returned no results.
If this is not expected, please check your split expression
How can I avoid this annoying log message. Should I wrap the foreach within a choice router that processes the foreach if there is atleast one element in the list. Any suggestions are welcome.
I would rather set the log level for org.mule.routing.Foreach$CollectionMapSplitter to ERROR than configure any additional logic for this warning. See Mule docs for configuring logger/log4j if you need to.