<flow name="datamappingFlow1" doc:name="datamappingFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="${hostname}" port="${port}" path="account" connector-ref="ConnectorWithoutMuleSession" doc:name="HTTP"/>
<jersey:resources doc:name="REST">
<component class="com.mycompany.qb.rest.AccountMappingService"/>
</jersey:resources>
<object-to-byte-array-transformer doc:name="Object to Byte Array"/>
<byte-array-to-object-transformer doc:name="Byte Array to Object"/>
<scatter-gather doc:name="upsert to db">
<flow-ref name="test1" doc:name="Flow Reference"></flow-ref>
<flow-ref name="test2" doc:name="Flow Reference"></flow-ref>
</scatter-gather>
</flow>
<flow name="test1" doc:name="test1">
<logger message="====Input deduction data is 1======#[payload]" level="INFO" doc:name="Logger"/>
<logger message="==== Input test1 data ======#[message.inboundProperties['City']]" level="INFO" doc:name="Logger"/>
<db:insert config-ref="Oracle_Configuration" doc:name="Database">
<db:parameterized-query><![CDATA[insert into test1(City)values(#[payload.City])]]></db:parameterized-query>
</db:insert>
</flow>
<flow name="test2" doc:name="test2">
<logger message="====Input deduction data is 2======#[payload]" level="INFO" doc:name="Logger"/>
<logger message="==== Input test2 data ======#[payload.City]" level="INFO" doc:name="Logger"/>
<db:insert config-ref="Oracle_Configuration" doc:name="Database">
<db:parameterized-query><![CDATA[insert into test2(City)values(#[payload.City])]]></db:parameterized-query>
</db:insert>
</flow>
Rest Component:
#Path("/")
public class AccountMappingService {
#POST
#Path("/mapping")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public String dataMapping(#Payload String content){
log.info("Rest Content is==>\n"+content);
return content;
}
Input data:
{
"City":"SFO1"
}
Output:
====Input deduction data is 2======{
"City":"SFO1"
}
==== Input test1 data ======null
====Input deduction data is 1======{
"City":"SFO1"
}
==== Input test2 data ======null
why I am getting null values here?
==== Input test1 data ======null
Comes from:
<logger message="==== Input test1 data ======#[message.inboundProperties['City']]" level="INFO" doc:name="Logger"/>
Inbound properties are set by the inbound endpoint. In your case, you're using an HTTP inbound endpoint. According to the doc:
To keep backward compatibility with previous versions of Mule, the headers and query parameters are also stored plain on the inbound properties.
So, unless you pass an HTTP header or query parameter named City in the HTTP request you send to your flow, the evaluation of #[message.inboundProperties['City']] can only return null.
The case of:
==== Input test2 data ======null
is different. It comes from:
<logger message="==== Input test2 data ======#[payload.City]" level="INFO" doc:name="Logger"/>
This calls .City on a payload of type String which can't work. I infer that the payload is of type String from:
public String dataMapping(#Payload String content)
You need to transform the JSON String payload into a java.util.Map if you want to extract values from it. From the doc you can see that you need to add a transformer:
<json:json-to-object-transformer returnClass="java.util.Map" />
USe Java map and then print them using a dot operation in logger, it will work.
Related
I have two flow one receive the xml payload and another json. I am routing the xml call to json flow using mule flow reference component after converting the xml to json payload. and second flow returns the json payload that i need to convert back to xml and reply to client.
My mule flow reference is throwing TransformerMsgException while receiving the json response from second flow.
Failed to transform from "json" to "java.lang.String" (org.mule.api.transformer.TransformerException). Message payload is of type: String
Here are the code for your reference -
<flow name="post:/chkdb:application/json:chkd-config">
<logger message="========json payload==>>>>==== #[message.payload]" level="INFO" doc:name="Logger"/>
<set-variable variableName="GGG_Number" value="#[json:ggg]" doc:name="Variable"/>
<!-- db call returns the payload-->
<choice doc:name="Choice">
<when expression="#[message.payload.size()>0]">
<set-payload value="{"indicator":"True"}" mimeType="application/json" doc:name="Set Payload"/>
</when>
<otherwise>
<set-payload value="{"indicator":"False"}" mimeType="application/json" doc:name="Set Payload"/>
</otherwise>
</choice>
<logger message="=========after producing json output=======" level="INFO" doc:name="Logger"/>
</flow>
<flow name="post:/chkdb:application/xml:chkdb-config">
<logger message="========= xml payload======== #[message.payload]" level="INFO" doc:name="Logger"/>
<json:xml-to-json-transformer mimeType="application/json" doc:name="XML to JSON"/>
<flow-ref name="post:/chkdb:application/json:chkdb-config" doc:name="post:/chkdb:application/json:chkdbapi-config"/> <!-- Getting exception here -->
<logger message=" after subflow call ==== #[message.payload]" level="INFO" doc:name="Logger"/>
<json:json-to-xml-transformer mimeType="application/xml" doc:name="JSON to XML"/>
<logger message="after json to xml conversion" level="INFO" doc:name="Logger"/>
</flow>
XML Request -
<ggg>DeJmp03bkqALlRFYmgu4+A==</ggg>
How i should retrieve the json response from other flow to current flow.
There is something missing here
First flow name: post:/chkdb:application/json:chkdbapi-config
Second flow name: post:/chkdb:application/xml:chkdbapi-config
Flow ref in second flow: post:/chkdb:application/json:chkdb-config
You are not referencing First flow.
So from your flow posted I can find few issues as follows :-
1. You are using where is the flow post:/chkdb:application/json:chkdb-config doesn't exits and it should be post:/chkdb:application/json:chkdbapi-config instead
2. Right now in the flow you are using <when expression="#[message.payload.size()>0]"> where as the message payload is in String format right now.
So, you can either use <when expression="#[message.payload.length()>0]">, using length() instead of size() or put a <json:json-to-object-transformer returnClass="java.lang.Object" doc:name="JSON to Object"/>before choice if you use #[message.payload.size()>0]
So the full code will be something as follows :-
<flow name="post:/chkdb:application/json:chkdbapi-config">
<logger message="========json payload==>>>>==== #[message.payload]" level="INFO" doc:name="Logger"/>
<!-- <json:json-to-object-transformer returnClass="java.lang.Object" doc:name="JSON to Object"/> --> <!-- incase you use #[message.payload.size()>0] in your choice -->
<!-- db call returns the payload-->
<set-variable variableName="GGG_Number" value="#[json:ggg]" doc:name="Variable"/>
<choice doc:name="Choice">
<when expression="#[message.payload.length()>0]">
<set-payload value="{"indicator":"True"}" mimeType="application/json" doc:name="Set Payload"/>
</when>
<otherwise>
<set-payload value="{"indicator":"False"}" mimeType="application/json" doc:name="Set Payload"/>
</otherwise>
</choice>
<logger message="=========after producing json output=======" level="INFO" doc:name="Logger"/>
</flow>
<flow name="post:/chkdb:application/xml:chkdbapi-config">
<logger message="========= xml payload======== #[message.payload]" level="INFO" doc:name="Logger"/>
<json:xml-to-json-transformer mimeType="application/json" doc:name="XML to JSON"/>
<flow-ref name="post:/chkdb:application/json:chkdbapi-config" doc:name="post:/chkdb:application/json:chkdbapi-config"/> <!-- Getting exception here -->
<logger message=" after subflow call ==== #[message.payload]" level="INFO" doc:name="Logger"/>
<json:json-to-xml-transformer mimeType="application/xml" doc:name="JSON to XML"/>
<logger message="after json to xml conversion" level="INFO" doc:name="Logger"/>
</flow>
How to convert type=java.lang.String to type=java.lang.Iterable as batch step (Process Records) is expecting type of java.lang.Iterable. Note : Input is an xml file and mule flow is a batch job.
When the xml has only one 'Report_Entry' record below error is recieved. For multiple entries of 'Report_Entry' flow works fine.
<object-to-string-transformer doc:name="Object to String"/>
<logger message="#[payload]" level="INFO" doc:name="Logger"/>
<set-payload
value="#[xpath3('/*:Report_Data/*:Report_Entry', payload, 'NODESET')]" doc:name="Set Payload"/>
<logger message="XML Record - #[payload]" level="INFO" doc:name="Logger"/>
</batch:input>
<batch:process-records>
<batch:step name="Batch_Step1">
<json:object-to-json-transformer doc:name="Object to JSON"/>
<logger message="XML Record - #[payload]" level="INFO" doc:name="Logger"/>
<amqp:outbound-endpoint exchangeName="${amqp.exchangeName}" queueName="${amqp.queueName}" responseTimeout="10000" encoding="UTF-8" mimeType="application/xml" connector-ref="AMQP_Connector" doc:name="AMQP"/>
</batch:step>
</batch:process-records>
In the logger it is printing 'org.mule.api.processor.LoggerMessageProcessor: XML Record - net.sf.saxon.dom.DOMNodeList#57d263b4' after the set-payload condition. Our requirement is to convert the xml record to JSON and write to AMQP.
That's because of the splitter. If you just want a collection/iterable before the batch job, jsut use set-payload:
<set-payload
value="#[xpath3('/*:Report_Data/*:Report_Entry', payload, 'NODESET')]" />
<batch:execute name="test" />
This should wok regardless of the amount nodes.
***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.
When I have XML payload from JMS inbound, XML to JAXB works as expected. But when I have same XML payload from HTTP inbound it throws an exception
An invalid return type "class [B" was specified for transformer "JAXBMarshallerTransformer" (org.mule.api.transformer.TransformerException)
Is it not a fair expectation from "XML to JAXB" component to have a XML payload from HTTP inbound? Please let me know what I am missing here.
Flow xml with with JMS and HTTP inbound. Only JMS inbound works as expected,
<flow name="productdemoFlow">
<jms:inbound-endpoint queue="my.test" connector-ref="Active_MQ" doc:name="JMS">
<jms:transaction action="NOT_SUPPORTED"/>
</jms:inbound-endpoint>
<logger message="#[payload]" level="INFO" doc:name="Logger"/>
<mulexml:jaxb-xml-to-object-transformer returnClass="com.chc.model.Product" jaxbContext-ref="JAXB_Context" doc:name="XML to JAXB Object"/>
<logger message="#[payload]" level="INFO" doc:name="Logger"/>
</flow>
<flow name="productdemoFlow1">
<http:listener config-ref="HTTP_Listener_Configuration" path="/test" allowedMethods="POST" doc:name="HTTP" />
<logger message="#["Payload ---------->" + payload.getClass().getName()]" level="INFO" doc:name="Logger"/>
<byte-array-to-string-transformer doc:name="Byte Array to String"/>
<logger message="#["Payload ---------->" + payload]" level="INFO" doc:name="Logger"/>
<mulexml:jaxb-xml-to-object-transformer encoding="windows-1252" mimeType="application/xml" jaxbContext-ref="JAXB_Context" doc:name="XML to JAXB Object"/>
</flow>
If I am not wrong, what you see is what you would expect.
The JMS inbound endpoint follows (by default, as in your case) a "one way" pattern, there is no response message to the client so there is no special requirement for the payload at the end of the flow.
The HTTP inbound endpoint follows (by default, as in your case) a "request-response" pattern so the payload, before sending the response to the client, should be of a type managed by the endpoint. In your case it is a java object instance of a not managed type, it must be converted to a correct type (String, InputStream, byte[], ...). For example:
<mulexml:jaxb-object-to-xml-transformer />
My mule flow:
<flow name="classmappingFlow1" doc:name="classmappingFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="${hostname}" port="${port}" path="insertClass" connector-ref="ConnectorWithoutMuleSession" doc:name="HTTP"/>
<jersey:resources doc:name="REST">
<component class="com.mycompany.mulesoft.rest.AccountMappingService"/>
</jersey:resources>
<json:json-to-object-transformer doc:name="JSON to Object"/>
<logger message="Payload======#[payload]" level="INFO" doc:name="Logger"/>
<logger message="=====Company===#[payload.Company]" level="INFO" doc:name="Logger"/>
<db:insert config-ref="Oracle_Configuration" doc:name="Database">
<db:parameterized-query><![CDATA[insert into SIAS_CONFIGURATION values(1, 1,1234,#[payload.Company],'Y','N','Y','you',sysdate,'you',sysdate)]]></db:parameterized-query>
</db:insert>
</flow>
Console:
Payload======[{"Company":"KLM","Class":"Y","Location":"N","Department":"Y","EmplId":"1234"}]
=====Company===null
JSON Data:
[
{
"Company":"KLM",
"Class":"Y",
"Location":"N",
"Department":"Y",
"EmplId":"1234"
}
]
Rest Component:
#POST
#Path("/setClass")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public String classSettings(#Payload String content){
return content;
}
Issue: I am getting null values and no data(empty) inserted to db
Use returnClass="java.util.List" in json:json-to-object-transformer after jersey:resources like the following :-
<json:json-to-object-transformer returnClass="java.util.List" doc:name="JSON to Object"/>