Mule Esb 3.2.1: gathering the results of a splitter and outputting results as XML - esb

I've been struggling through SO and the Mule forums but can't find a solution that works. The esb takes in a single request containing an id, which creates an XML payload that is composed a list of related ids. This XML payload is then split and sent to a transformer that takes each related id to get some meta data. The results are then supposed to be combined together to make an XML response. The problem I am having is that no matter how I transform the final result set, I always get back the document with an encapsulating string "??sr)java.util.concurrent.CopyOnWriteArrayListx]....""x
Any ideas/comments would be greatly appreciated.
Here is the mule-config I am using:
<http:connector name="HttpConnector" doc:name="HTTP\HTTPS"/>
<expression-transformer name="ExtractId" doc:name="Expression">
<return-argument evaluator="xpath" expression="//string[1]"/>
</expression-transformer>
<flow name="myFlow1" doc:name="myFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" path="incoming/path/" connector-ref="HttpConnector" doc:name="HTTP"/>
<custom-transformer encoding="UTF-8" class="mycomponents.transformers.SubscriberRequestTransformer" doc:name="Create Hub Id Requests"/>
<mulexml:object-to-xml-transformer doc:name="Object to XML"/>
<splitter evaluator="xpath" expression="//entry/list/string" enableCorrelation="ALWAYS" doc:name="Splitter"/>
<transformer ref="ExtractId" doc:name="Transformer Reference"/>
<logger message="#[payload:]" level="INFO" doc:name="Logger"/>
<custom-transformer encoding="UTF-8" class="mycomponents.transformers.HubQueryProcessor" doc:name="Create Hub Id Requests"/>
<collection-aggregator />
<component class="mycomponents.TopicResponseAggregatorComponent" doc:name="Collect requests" />
<logger message="Aggregated Content (#[groovy:payload.size()] elements): \n#[payload:]" level="INFO" doc:name="Logger"/>
<logger message="#[payload:]" level="INFO" doc:name="Logger"/>
</flow>
I've resolved the issue. Although I don't quite understand why it's different but I'm assuming it has to do with some of the mule "magic". I split up the flow into multiple flows which is what I was eventually going to do anyways. However, by doing this the problem went away.
FYI: here's the updated flow:
<flow name="myFlow1" doc:name="myFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" path="url/for/service/" connector-ref="HttpConnector" doc:name="HTTP"/>
<flow-ref name="createHubIdRequestsFlow" doc:name="Map To Hub Ids" doc:description="Takes in the situation id passed in by the client. Does the query lookup versus the content mapping tables. creates the correspondng requests for meta data information to the provider(s)"/>
<flow-ref name="getTopicRequests" doc:name="Process Provider Reponses" doc:description="For each JSON response returned from the provider, transform it into an XML representation of that data"/>
<flow-ref name="buildResponseFlow" doc:name="Build final response" doc:description="piece all the messages together into a single object as a string"/>
<response>
<message-properties-transformer>
<add-message-property value="text/xml" key="Content-Type" />
</message-properties-transformer>
</response>
</flow>

By default, the message properties transformer stores new properties in the "invocation" scope. You need to set the content-type on the "outbound" scope so it is used by the inbound HTTP endpoint in its response phase.
Try this:
<response>
<message-properties-transformer scope="outbound">
<add-message-property value="text/xml" key="Content-Type" />
</message-properties-transformer>
</response>

Related

Mule: reuse a foreach payload and run it again through another foreach component

I have a simple csv-to-pojo datamapper, which gets sent to two synchronous flow through an "All" flow control component. The first flow runs the payload through a Foreach, then once it is done, the second flow attempts to run the payload from the datamapper again through a different foreach, but instead I'm getting this warning message:
Splitter returned no results. If this is not expected, please check your split expression.
Furthermore, it seems that Mule only allows me to run the payload through either flow one or flow two, but not both. Again, running it trough more than one Foreach component will result in the Splitter warning.
Any help will be appreciated. Thanks in advance. Here's the setup:
<flow name="main_flow" doc:name="main_flow" initialState="started" processingStrategy="synchronous">
<data-mapper:transform config-ref="csv_to_pojo" doc:name="CSV To Pojo" stream="true"/>
<all doc:name="All">
<flow-ref name="flow1" doc:name="Flow Reference"/>
<flow-ref name="flow2" doc:name="Flow Reference"/>
</all>
</flow>
<flow name="flow1" doc:name="flow1" processingStrategy="synchronous">
<logger message="Entering flow 1" level="INFO" doc:name="Logger"/>
<foreach doc:name="For Each">
<logger message="Inside foreach of flow1 " level="INFO" doc:name="Logger"/>
</foreach>
</flow>
<flow name="flow2" doc:name="flow2" processingStrategy="synchronous">
<logger message="Entering flow2" level="INFO" doc:name="Logger"/>
<foreach doc:name="For Each">
<logger message="Inside foreach of flow2" level="INFO" doc:name="Logger"/>
</foreach>
</flow>

Mule ESB: How to use a flow execution conditional on a JSON object

Mule ESB
I am trying to convert a Hello World program into a program that will accept a JSON object, examine the data, and route the execution accordingly.
Below is a copy of my flow:
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:json="http://www.mulesoft.org/schema/mule/json" version="EE-3.5.0" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:core="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation" xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns:spring="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/json http://www.mulesoft.org/schema/mule/json/current/mule-json.xsd">
<json:object-to-json-transformer name="Object_to_JSON" doc:name="Object to JSON"/>
<flow doc:name="HelloWorldFlow1" name="HelloWorldFlow1">
<http:inbound-endpoint doc:description="This endpoint receives an HTTP message." doc:name="HTTP" exchange-pattern="request-response" host="localhost" port="8081" contentType="application/json"/>
<echo-component doc:name="Echo"/>
</flow>
</mule>
I see the object-to-json in the code, which I believe is configured from the
HTTP Node->HTTP Settings->content type, which is set to
application/json
So I assume that the incoming object is in JSON format once within the flow, with no fursther Object to JSON nodes required.
I am sending the following string to the flow:
{ "uid" : "ABCxxx" }
What I am trying to achieve to get a node that will examine and verify that the first three letters of the uid is "ABC", and if so send it down one path, but if the first three characters of the uid does not equal "ABC", to go down another path., sort of like a IF statement with a true and a false configtion,
The following is a Pseudo code example
IF uid[3] == "ABC"
GOTO Database Connector
else
GOTO JSON-TO-OBJECT Transformer
My question is: Whhich node should I use to perform this, should I use an Expression filter or other
... and how do I write that in JSAONPath (or other)
(Does Mule ESB perform this sort of thing?)
Th json evaluator that executes JsonPath in mule is deprecated in favor of MEL. The preferred approach now is to convert json to an object and query the object instead. One of the simplest approaches is to convert the json to the map and use MEL to query the map. Like so:
<json:json-to-object-transformer returnClass="java.util.HashMap" />
<choice>
<when expression="#[payload.uid == 'ABC']">
</when>
</choice>
More info here: http://www.mulesoft.org/documentation/display/current/Mule+Expression+Language+Tips
You can also <json:json-to-object-transformer returnClass="java.lang.Object" /> alternatively
and then
<choice>
<when expression="#[message.payload.uid == 'ABC']">

Why is Mule exception strategy so chatty?

In my Mule app, I've configured some of the flows to use a catch exception strategy in order to do some special processing. For these cases, I want to pop the error and the original payload into an object store. Everywhere else, the default exception strategy is fine.
<flow name="saveLookup">
<vm:inbound-endpoint exchange-pattern="one-way" ref="Lookup_Save_VM" />
<component>
<spring-object bean="insertLookupMDCvalues"/>
</component>
<set-variable variableName="originalPayload" value="#[payload]"/>
<json:json-to-object-transformer returnClass="com.company.LookupData"/>
<set-variable variableName="transactionId" value="#[payload.transactionId]"/>
<transactional action="ALWAYS_BEGIN">
<logger message="${lookup.SQL}" level="INFO"/>
<jdbc:outbound-endpoint exchange-pattern="request-response" queryKey="saveLookup" queryTimeout="-1" connector-ref="JdbcConnector" />
<foreach collection="#[payload.transactional.lookupItems.items]">
<logger message="${lookup.item.SQL}" level="INFO" />
<jdbc:outbound-endpoint exchange-pattern="request-response" queryKey="saveLookupItem" queryTimeout="-1" connector-ref="JdbcConnector"/>
</foreach>
</transactional>
<component>
<spring-object bean="clearLookupMDCvalues"/>
</component>
<catch-exception-strategy>
<message-properties-transformer scope="invocation">
<add-message-property key="errorMap" value="#[['id' : transactionId, 'body' : originalPayload, 'error' : exception.summaryMessage]]"/>
</message-properties-transformer>
<choice>
<when expression="#[message.inboundProperties['resubmit']]">
<logger message="Resubmission of lookup data failed, saving to Dead Letter object store. ID=#[transactionId]" level="INFO"/>
<objectstore:store config-ref="lookupDeadLetterOS" key="#[transactionId]" overwrite="true" value-ref="#[errorMap]"/>
</when>
<otherwise>
<logger message="Saving lookup data failed, saving to Error object store. ID=#[transactionId]" level="INFO"/>
<objectstore:store config-ref="lookupErrorOS" key="#[transactionId]" overwrite="true" value-ref="#[errorMap]"/>
</otherwise>
</choice>
<set-payload value="Error: #[exception.summaryMessage]"/>
<component>
<spring-object bean="clearLookupMDCvalues"/>
</component>
</catch-exception-strategy>
</flow>
My problem is that when an error is encountered, let's say a Null Pointer Exception in the foreach component, I'm seeing four ERROR log statements for each event:
Exception stack is: 1. null (java.lang.NullPointerException) ...and so on. This is logged twice.
CatchMessagingExceptionStrategy - Message : Execution of the expression "payload.transactional.lookupItems.items" failed. (org.mule.api.expression.ExpressionRuntimeException). Message payload is of type: LookupData
DefaultMessagingExceptionStrategy - Message : Execution of the expression "payload.transactional.lookupItems.items" failed. (org.mule.api.expression.ExpressionRuntimeException). Message payload is of type: LookupData
I thought that a flow-specific exception strategy should override the default strategy. Why the duplicate log messages, and is there a way to shush them? I'd like to avoid having to configure the default exception strategy, as it's perfectly acceptable behavior in the majority of the flows.
The issue is that the built in exception strategies inherit from AbstractExceptionListener, and they all use the logException template method. The base implementation always logs at ERROR level, which is sometimes not appropriate for your application.
You can create a simple subclass of CatchMessagingExceptionStrategy that overrides the logException method, and logs however you want. Then, use it in your flow in place of the <catch-exception-strategy> like so:
<custom-exception-strategy class="com.mycompany.mule.QuietCatchExceptionStrategy">
<!-- your message processors here -->
</custom-exception-strategy>

Mule ESB: Converting JSON Object to another object

I have the following flow:
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:json="http://www.mulesoft.org/schema/mule/json" xmlns:db="http://www.mulesoft.org/schema/mule/db" xmlns:tracking="http://www.mulesoft.org/schema/mule/ee/tracking" xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
xmlns:spring="http://www.springframework.org/schema/beans" version="EE-3.5.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/db http://www.mulesoft.org/schema/mule/db/current/mule-db.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/ee/tracking http://www.mulesoft.org/schema/mule/ee/tracking/current/mule-tracking-ee.xsd
http://www.mulesoft.org/schema/mule/json http://www.mulesoft.org/schema/mule/json/current/mule-json.xsd">
<db:generic-config name="Generic_Database_Configuration" url="jdbc:db2://localhost:50000/TEST:user=instuid;password=instpw;" driverClassName="com.ibm.db2.jcc.DB2Driver" doc:name="Generic Database Configuration"/>
<flow name="test2Flow1" doc:name="test2Flow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" doc:name="HTTP"/>
<db:select config-ref="Generic_Database_Configuration" doc:name="Database" doc:description="test">
<db:parameterized-query><![CDATA[SELECT SUM(BAL) FROM xxxx.ACCT]]></db:parameterized-query>
</db:select>
<json:object-to-json-transformer doc:name="Object to JSON"/>
</flow>
</mule>
The flow words well, and as you can see the JSON object converts the Database object to the following:
(A JSON arry with a single object):
[{"1":444}]
Notice that the 444 is a numeric value (it does not have quotes around it).
What I want to do
Create a simple JSON structure without an array
Change the 444 from a numeric value to a string value
Make it look something like: (placing the 444 into another structure)
{ "Total" : "444", "Date" : "14/07/14" }
I know that to get the system date, I perform the following:
#[server.dateTime.format('dd/MM/yy')]
... and I know to get the 444 value from the original string, I performed the following:
$..1
But I do not know what to do next.
Now that I used a JSON object to view the results of the database connector, what object do I do next to create my new structure.
Do I use another JSON object, how would I structure the expression ?
To write all numbers as strings you can set it on the Jackson object mapper and reference that custom object mapper from your transformer:
<spring:beans>
<spring:bean id="jacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper" />
<spring:bean
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<spring:property name="targetObject" ref="jacksonObjectMapper" />
<spring:property name="targetMethod" value="configure" />
<spring:property name="arguments">
<spring:list>
<spring:value>WRITE_NUMBERS_AS_STRINGS</spring:value>
<spring:value>true</spring:value>
</spring:list>
</spring:property>
</spring:bean>
</spring:beans>
<flow name="flow1" doc:name="flow1">
...
<json:object-to-json-transformer mapper-ref="jacksonObjectMapper" />
...
</flow>
However this will dot it for all number fields. You might have to write a custom serializer for specific behaviour.
As for unwrapping the array. Not sure you can do this via the object mapper with the jackson version mule uses. But for this case, if your always just getting one result back from the query - you could possibly just unfold the array before the json transformer
<set-payload value="#[payload[0]]">
<json:object-to-json-transformer mapper-ref="jacksonObjectMapper" />
A simple way of doing is to use Mule's Expression Transformer.
You need to extract the values from your JSON array and store it into some variables like the following :-
<json:json-to-object-transformer returnClass="java.util.List" doc:name="JSON to Object" />
<set-variable variableName="Total" value="#[message.payload[0].1]" doc:name="Variable" />
Now, your variable Total will contain the value 444
Next step is to store your Date into some other variable as follows :-
<set-variable variableName="Date" value="#[server.dateTime.format('dd/MM/yy')]" doc:name="Variable" />
Now, if these 2 steps are done, then you can create your required JSON in a very easy way using Expression Transformer as follows :-
<expression-transformer
expression="#[[
'Total': flowVars['Total'].toString(),
'Date': flowVars['Date']
]]" doc:name="Expression" />
<json:object-to-json-transformer doc:name="Object to JSON" />
This will produce and structure your required JSON :- {"Date":"12/08/15","Total":"444"} in a very easy way

how may i select the values based on where condition in Mule ESB

I am new for MuleESB. I don't have much knowledge about flow. I couldn't find proper documentation for Mule. I am trying to fetch the data from database using below code, but I am unable fetch the data. There is no error shown, so I dont know what to do. Is my flow correct?
Here's my flow config.
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:jdbc-ee="http://www.mulesoft.org/schema/mule/ee/jdbc" xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns:json="http://www.mulesoft.org/schema/mule/json" xmlns:mulexml="http://www.mulesoft.org/schema/mule/xml" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation" xmlns:spring="http://www.springframework.org/schema/beans" version="EE-3.4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/xml http://www.mulesoft.org/schema/mule/xml/current/mule-xml.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/ee/jdbc http://www.mulesoft.org/schema/mule/ee/jdbc/current/mule-jdbc-ee.xsd
http://www.mulesoft.org/schema/mule/json http://www.mulesoft.org/schema/mule/json/current/mule-json.xsd">
<jdbc-ee:postgresql-data-source name="PostgreSQL_Data_Source" user="youtilitydba" password="Youtility11" url="jdbc:postgresql://localhost:5432/sample" transactionIsolation="UNSPECIFIED" doc:name="PostgreSQL Data Source"/>
<jdbc-ee:connector name="Database" dataSource-ref="PostgreSQL_Data_Source" validateConnections="true" queryTimeout="-1" pollingFrequency="0" doc:name="Database"/>
<flow name="selectfromdbFlow1" doc:name="selectfromdbFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" path="selectdb" doc:name="HTTP"/>
<json:json-to-object-transformer returnClass="java.util.Map" doc:name="JSON to Object"/>
<jdbc-ee:outbound-endpoint exchange-pattern="one-way" queryKey="SELECT" queryTimeout="-1" connector-ref="Database" doc:name="Database">
<jdbc-ee:query key="SELECT" value="select firstname,lastname,id from users where id =#[message.payload.id]"/>
</jdbc-ee:outbound-endpoint>
<response>
<http:response-builder status="200" contentType="application/json" doc:name="HTTP Response Builder"/>
</response>
<set-payload value="#[payload]" doc:name="Set Payload"/>
<echo-component doc:name="Echo"/>
</flow>
</mule>
I am sending request from curl client like this
curl -H "Content-Type: application/json" -d '{"id":"5"}' http://192.168.25.24:8081/selectdb
It doesn't provide and response back.
I am expecting a response like the one below.
{"Body":{"Datalist":{"firstname":"ff","lastname":"ggg","id":"5"}},"Status":"200"}}
Please help me acheive this.
Even the logger statement is not printing
<logger message="message of payload#[message.payload]" level="INFO" doc:name="Logger"/>
Appreciate any help.
You can better use <json:json-to-object-transformer returnClass="java.lang.Object" doc:name="JSON to Object"/> after http:inbound-endpoint and make sure if you are getting the id value from request and after payload after db
Now, if you are getting the data from your db and able to print it using a logger after db using
<logger message="message of payload #[message.payload]" level="INFO" doc:name="Logger"/>
You can explicitly set your response to your client in following way :-
<http:response-builder status="200" contentType="application/json" doc:name="HTTP Response Builder">
<set-payload value="#[message.payload]" doc:name="Set Payload"/>
</http:response-builder>
and you can remove the <response/> tag from your flow, as you are setting your response payload using <http:response-builder/> as above
I can't answer your question fully, but can tell you few easy ways to inspect your muleMessage.
the first and easiest way is to place a script transformer like this:
<script:transformer>
<script:script engine="groovy">
<script:text>
System.out.println(payload);
return payload;
</script:text>
</script:script>
</script:transformer>
namespace: xmlns:script="http://www.mulesoft.org/schema/mule/scripting"
schemaLocation: http://www.mulesoft.org/schema/mule/scripting http://www.mulesoft.org/schema/mule/scripting/current/mule-scripting.xsd
second option and harder one would be creating custom transformer. U'll need to create a java class, extend the AbstractMessageTransformer. Then debug your project and see what's the message
hope, this will help
Couldn't get the complete issue you are facing. From the post I can see there are few changes to be made.
As you are looking for data back from Select Query change the exchange-pattern on the JBDC:Outbound to request-response
<jdbc-ee:outbound-endpoint exchange-pattern="request-response" queryKey="SELECT" queryTimeout="-1" connector-ref="Database" doc:name="Database">
Also there is no need of the <set-payload> at the end of the flow. As the payload is already available in the message, this is a redundant statement.
In the logger try using #[payload] as it is more simple to print your payload (response from JBDC query)
About documentation, MuleSoft website is the best place to find documentation about mule They have a detailed documentation for most of the things of Mule.
Mule User Guide and Documentation
Hope this helps.