Mule: transform the results of outbound-endpoint - mule

The following flow transforms incoming an JSON payload into a SOAP message which is used in a subflow to make a webservice request. Everything works fine -- i'm able to send a response back for the original (incoming) request, but I want to add a final step to transform the SOAP result into JSON before sending it back to the client.
Here is the flow:
<mule ...>
<data-mapper:config name="json2xml_grf" transformationGraphPath="json2xml.grf" doc:name="DataMapper"/>
<flow name="simpleFlow" doc:name="simpleFlow">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" doc:name="HTTP"/>
<set-property propertyName="Access-Control-Allow-Origin" value="*" doc:name="Property"/>
<choice doc:name="Choice">
<when expression="#[message.inboundProperties['http.method'] != 'OPTIONS']">
<data-mapper:transform config-ref="json2xml_grf" doc:name="DataMapper"/>
<flow-ref name="invokeCalculatorService" doc:name="invokeCalculator"/>
</when>
<otherwise>
<http:response-builder status="200" doc:name="HTTP Response Builder">
...
</http:response-builder>
</otherwise>
</choice>
</flow>
<flow name="invokeService" doc:name="invokeService">
<cxf:proxy-client payload="body" enableMuleSoapHeaders="true" doc:name="Proxy Client">
</cxf:proxy-client>
<mulexml:xslt-transformer maxIdleTransformers="2" maxActiveTransformers="5" xsl-file="/Users/jsleeuw/MuleStudio/workspace/calc/src/main/resources/transformsoap.xslt" doc:name="XSLT"/>
<http:outbound-endpoint exchange-pattern="request-response" doc:name="CalculatorService" method="POST" host="service-host" port="30001"/>
</flow>
</mule>
Putting a DataMapper at the end of the subflow like this:
...
<flow-ref name="invokeCalculatorService" doc:name="invokeCalculator"/>
<data-mapper:transform config-ref="xml2json_grf" doc:name="DataMapper"/>
...
Results in this error:
********************************************************************************
Message : Error executing graph: ERROR (com.mulesoft.mule.module.datamapper.api.exception.DataMapperExecutionException). Message payload is of type: DepthXMLStreamReader
Code : MULE_ERROR--2
--------------------------------------------------------------------------------
Exception stack is:
1. Content is not allowed in prolog. (org.xml.sax.SAXParseException)
org.apache.xerces.util.ErrorHandlerWrapper:-1 (null)
2. org.xml.sax.SAXParseException: Content is not allowed in prolog. (net.sf.saxon.trans.DynamicError)
net.sf.saxon.event.Sender:308 (null)
3. XPath evaluation failed (org.jetel.exception.JetelRuntimeException)
org.jetel.component.tree.reader.xml.XmlXPathEvaluator:81 (null)
4. Error executing graph: ERROR (com.mulesoft.mule.module.datamapper.api.exception.DataMapperExecutionException)
com.mulesoft.mule.module.datamapper.impl.DefaultGraphExecutor:83 (null)
5. Error executing graph: ERROR (com.mulesoft.mule.module.datamapper.api.exception.DataMapperExecutionException). Message payload is of type: DepthXMLStreamReader (com.mulesoft.mule.module.datamapper.processors.DataMapperMessageExecutionException)
com.mulesoft.mule.module.datamapper.processors.DataMapperMessageProcessor:135 (null)
--------------------------------------------------------------------------------
Whereas putting the datamapper at the end of the subflow ends up blocking the response.
How should I go about transforming my response?

From the Content is not allowed in prolog exception it seems that <flow-ref name="invokeCalculatorService" /> doesn't return a payload that is parseable as XML.
This sub-flow returns a org.apache.cxf.staxutils.DepthXMLStreamReader, which is an javax.xml.stream.XMLStreamReader. The only transformer I know of that can deserialize this type to an XML string is: <mulexml:dom-to-xml-transformer />.
Can you add one just before the data-mapper element?

Related

Mule Exception strategy definition: Invalid content was found starting with element 'choice-exception-strategy'

I'm developing a mule work-flow to insert a record into the database, trying to catch the exception in case if the record is already present and send the HTTP status (409-Conflict) and the back to the client.
<when expression="#[message.inboundProperties['http.method'] == 'POST']">
<json:json-to-object-transformer returnClass="java.lang.Object" doc:name="JSON to Object" />
<set-variable variableName="id" value="#[message.payload.id]" doc:name="Save brandId"/>
<json:object-to-json-transformer doc:name="Object to JSON"/>
<db:insert config-ref="Postgres" doc:name="Configstore">
<db:parameterized-query><![CDATA[INSERT INTO messages("id", "data") VALUES ( #[flowVars['id']], CAST(#[message.payload] as json))]]> </db:parameterized-query>
</db:insert>
<logger message="REST Response = #[message.payload]" level="INFO" doc:name="LOG Rest Response"></logger>
<choice-exception-strategy name="Global_Choice_Exception_Strategy" doc:name="Global Choice Exception Strategy">
<catch-exception-strategy doc:name="Catch_Exception_Strategy" when="#[exception.causedBy(org.postgresql.util.PSQLException)]">
<set-payload value="The request cannot be processed, the error is #[exception.getExceptionPayload()]"/>
<set-property propertyName="http.status" value="404"/>
<http:outbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" method="POST" doc:name="HTTP"/>
</catch-exception-strategy>
</choice-exception-strategy>
</when>
The start-up is repeatedly failing and the following error reported in the logs.
cvc-complex-type.2.4.a: Invalid content was found starting with element 'choice-exception-strategy'. One of '{"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) ~[?:?]
This error alternatively reported for both choice-exception-strategy and catch-exception-strategy. Not sure what's invalid here or need to define a custom message-processor or outbound-endpoint. I'm using mule EE-3.8.0
The problem is that you are using an exception strategy within a choice element. The exception strategy must be defined for your whole flow, not single elements (some do allow them though but are rare cases). You can find more on this here and an example here.
HTH

JAXB with HTTP inbounds throws exception An invalid return type "class [B" was specified for transformer "JAXBMarshallerTransformer"

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 />

Json to object and Mule expression

I have a json file which the link is https://gist.githubusercontent.com/Rajeun/b550fe17181610f5c0f0/raw/7ba82c6c1135d474e0bedc8b203d3cf16e196038/file.json
i want to do a test on the boolean "sent". there is my xml file.
<http:request-config name="HTTP_Request_Configuration"
host="gist.githubusercontent.com" port="443" protocol="HTTPS"
doc:name="HTTP Request Configuration" />
<flow name="testFlow">
<poll doc:name="Poll">
<http:request config-ref="HTTP_Request_Configuration"
path="Rajeun/b550fe17181610f5c0f0/raw/7ba82c6c1135d474e0bedc8b203d3cf16e196038/file.json"
method="GET" doc:name="HTTP" />
</poll>
<json:json-to-object-transformer
returnClass="java.lang.Object" doc:name="JSON to Object" />
<choice doc:name="Choice">
<when expression="#[payload.sent] == true )">
<logger message="its ok" level="INFO" doc:name="Logger"/>
</when>
<otherwise>
<logger message="Error" level="INFO" doc:name="Logger"/>
</otherwise>
</choice>
</flow>
errors:
ERROR 2015-03-25 16:29:59,871 [[push1].testFlow.stage1.02] org.mule.exception.DefaultMessagingExceptionStrategy:
********************************************************************************
Message : Failed to transform from "json" to "java.lang.Object"
Code : MULE_ERROR-109
--------------------------------------------------------------------------------
Exception stack is:
1. Unexpected character ('"' (code 34)): was expecting comma to separate OBJECT entries
at [Source: java.io.InputStreamReader#1a09a5b; line: 5, column: 4] (org.codehaus.jackson.JsonParseException)
org.codehaus.jackson.JsonParser:1433 (null)
2. Failed to transform from "json" to "java.lang.Object" (org.mule.api.transformer.TransformerException)
org.mule.module.json.transformers.JsonToObject:132 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/transformer/TransformerException.html)
--------------------------------------------------------------------------------
Root Exception stack trace:
org.codehaus.jackson.JsonParseException: Unexpected character ('"' (code 34)): was expecting comma to separate OBJECT entries
at [Source: java.io.InputStreamReader#1a09a5b; line: 5, column: 4]
at org.codehaus.jackson.JsonParser._constructError(JsonParser.java:1433)
at org.codehaus.jackson.impl.JsonParserMinimalBase._reportError(JsonParserMinimalBase.java:521)
at org.codehaus.jackson.impl.JsonParserMinimalBase._reportUnexpectedChar(JsonParserMinimalBase.java:442)
+ 3 more (set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
i don't know what is the problem please any help !!
The expression should be <when expression="#[payload.sent == true ]"> and this is working for me ..
also as afelisatti mentioned, there should be a comma after email attribute in JSON payload
There's is no comma after the "email" in that JSON file so the transformation fails, that's what the error message is saying. I believe the correct format would be
{
"token" : 123,
"tel" : 456,
"email" : "Rm9vYmFyIQ==",
"sent" : true
}
Remove
<json:json-to-object-transformer returnClass="java.lang.Object" doc:name="JSON to Object" />
and use an json based mule expression #[json:sent]

mule java.lang.reflect.Method cannot be cast to java.lang.String (java.lang.ClassCastException)

We are getting an error while using proxy client to send an XML to a web service. Here is the configuration:
<flow name="CreateDIMEntry" doc:name="CreateDIMEntry">
<vm:outbound-endpoint exchange-pattern="one-way" path="DIM_VM" doc:name="VM"/>
<byte-array-to-string-transformer doc:name="Byte Array to String"/>
<mulexml:xslt-transformer maxIdleTransformers="2" maxActiveTransformers="5" xsl-file="D:\Users\vkamat\Desktop\dim\src\main\resources\addenvelopetopayload.xsl" doc:name="XSLT"/>
<byte-array-to-string-transformer doc:name="Byte Array to String"/>
<logger message="I am here..#[message.payload]" level="INFO" doc:name="Logger"/>
<set-property propertyName="SOAPAction" value="urn:com.org.ProcessActivity" doc:name="Property"/>
<set-property propertyName="Content-Type" value="application/soap+xml" doc:name="Property"/>
<!-- <set-property propertyName="SOAPAction" value="urn:com.org.ProcessActivity" doc:name="Property"/> -->
<cxf:proxy-client doc:name="SOAP" payload="envelope">
</cxf:proxy-client >
<http:outbound-endpoint exchange-pattern="request-response" host="${dim.host}" port="${dim.port}" method="POST" doc:name="HTTP" path="${dim.path}">
</http:outbound-endpoint>
</flow>
when called this flow with testing flow as below, it works fine
<flow name="DimFlow1" doc:name="DimFlow1">
<file:inbound-endpoint path="D:\Documents\test" responseTimeout="10000" doc:name="File"/>
<flow-ref name="CreateDIMEntry" doc:name="Flow Reference"/>
</flow>
But when integrated in another flow, it gives an error, Giving snippet of main flow from where it is getting called
<async doc:name="Async">
<mulexml:object-to-xml-transformer doc:name="Object to XML"/>
<mulexml:xslt-transformer maxIdleTransformers="2" maxActiveTransformers="5" xsl-file="D:\addenvelopetopayload.xsl" doc:name="XSLT"/>
<logger message="before DIM-- #[message.payload]" level="INFO" doc:name="Logger"/>
<flow-ref name="CreateDIMEntry" doc:name="Flow Reference"/>
</async>
The error encountered is
********************************************************************************
Message : java.lang.reflect.Method cannot be cast to java.lang.String. Failed to route event via endpoint: org.mule.module.cxf.CxfOutboundMessageProcessor. Message payload is of type: ReversibleXMLStreamReader
--------------------------------------------------------------------------------
Exception stack is:
1. java.lang.reflect.Method cannot be cast to java.lang.String (java.lang.ClassCastException)
org.mule.module.cxf.CxfOutboundMessageProcessor:338 (null)
2. java.lang.reflect.Method cannot be cast to java.lang.String. Failed to route event via endpoint: org.mule.module.cxf.CxfOutboundMessageProcessor. Message payload is of type: ReversibleXMLStreamReader (org.mule.api.transport.DispatchException)
org.mule.module.cxf.CxfOutboundMessageProcessor:150 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/transport/DispatchException.html)
--------------------------------------------------------------------------------
Root Exception stack trace:
java.lang.ClassCastException: java.lang.reflect.Method cannot be cast to java.lang.String
at org.mule.module.cxf.CxfOutboundMessageProcessor.getMethodOrOperationName(CxfOutboundMessageProcessor.java:338)
at org.mule.module.cxf.CxfOutboundMessageProcessor.getOperation(CxfOutboundMessageProcessor.java:356)
at org.mule.module.cxf.CxfOutboundMessageProcessor.doSendWithClient(CxfOutboundMessageProcessor.java:212)
+ 3 more (set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
********************************************************************************
Try setting the following before the CXF client:
<set-variable value="#[flowVars['cxf_operation'].getLocalPart()]" variableName="operation" />

Mule: How to use until successfull processor for service calls

Please help me on this logic. I have to call the service and get the response back.If the service is down or something have to retry 3 times and once exhausted need to log in DLQ.I'm using until successful processor.For success scenario i'm getting only null payload in logger.But i tried keeping the HTTP outbound end point without until successfull able to get the response from the service. Please find my xml config.
<flow name="Flow" doc:name="eFlow" tracking:enable-default-events="true">
<wmq:inbound-endpoint queue="InputQ" tracking:enable-default-events="true" connector ref="WMQ_Connector" doc:name="connector">
<wmq:transaction action="NONE"/>
</wmq:inbound-endpoint>
<mulexml:dom-to-xml-transformer></mulexml:dom-to-xml-transformer>
<set-session-variable variableName="originalPayload" value="#[payload]" doc:name="Store_Payload"/>
<choice tracking:enable-default-events="true" doc:name="Choice">
<when expression="#[xpath('fn:local-name(/root/*[2])') == 'Master']">
<data-mapper:transform config-ref="Master_grf" doc:name="Master"/>
</when>
<when expression="#[xpath('fn:local-name(/root/*[2])') == 'Request']">
<data-mapper:transform config-ref="Request_grf" doc:name="Bulk"/>
</when>
<otherwise>
<scripting:component doc:name="Throw_Exception">
<scripting:script engine="Groovy"><![CDATA[throw new IllegalArgumentException ('requests invalid') ]]>
</otherwise>
</choice>
<mulexml:dom-to-xml-transformer></mulexml:dom-to-xml-transformer>
<flow-ref name="Invoke_Service" doc:name="Flow Reference"/>
</flow>
<flow name="Invoke_Service" doc:name="Invoke_Service" tracking:enable-default-events="true">
<cxf:jaxws-client enableMuleSoapHeaders="true" doc:name="SOAP" operation="Request" serviceClass="com.valid.ICase"/>
<until-successful objectStore-ref="objectStore" maxRetries="3" secondsBetweenRetries="2" deadLetterQueue-ref="VM" doc:name="UntilSuccessful_SymboticService">
<http:outbound-endpoint exchange-pattern="request-response" method="POST" doc:name="HTTP" address="http://localhost:1112/symbotic"/>
</until-successful>
<byte-array-to-string-transformer doc:name="Byte Array to String"/>
<logger message="**********success***Payload: #[payload]*****" level="INFO" doc:name="Logger"/>
But incase of failure scenario until success retry 3 times ( works fine). I have tried request reply processor inside until also transactional processor. It is not working. Using Mule version 3.4.kindly suggest me.
Retried the same with request -reply processor as per the suggestion
<flow name="Flow" doc:name="eFlow" tracking:enable-default-events="true">
<wmq:inbound-endpoint queue="InputQ" tracking:enable-default-events="true" connector- ref="WMQ_Connector" doc:name="connector">
<wmq:transaction action="NONE"/>
</wmq:inbound-endpoint>
<mulexml:dom-to-xml-transformer></mulexml:dom-to-xml-transformer>
<set-session-variable variableName="originalPayload" value="#[payload]" doc:name="Store_Payload"/>
<choice tracking:enable-default-events="true" doc:name="Choice">
<when expression="#[xpath('fn:local-name(/root/*[2])') == 'Master']">
<data-mapper:transform config-ref="Master_grf" doc:name="Master"/>
</when>
<when expression="#[xpath('fn:local-name(/root/*[2])') == 'Request']">
<data-mapper:transform config-ref="Request_grf" doc:name="Bulk"/>
</when>
<otherwise>
<scripting:component doc:name="Throw_Exception">
<scripting:script engine="Groovy"><![CDATA[throw new IllegalArgumentException('requests other then Master andRequest') ]]>
</otherwise>
</choice>
<mulexml:dom-to-xml-transformer></mulexml:dom-to-xml-transformer>
<request-reply timeout="10000">
<vm:outbound-endpoint path="request"/>
<vm:inbound-endpoint path="reply"/>
</request-reply>
<byte-array-to-string-transformer doc:name="Byte Array to String"/>
<logger message="**********success***Payload: #[payload]*****" level="INFO" doc:name="Logger"/>
</flow>
<flow name="Invoke_Service" doc:name="Invoke_Service" tracking:enable-default-events="true">
<vm:inbound-endpoint path="request" doc:name="VM"/>
<cxf:jaxws-client enableMuleSoapHeaders="true" doc:name="SOAP" operation="Request" serviceClass="com.valid.ICase"/>
<until-successful objectStore-ref="objectStore" maxRetries="3" secondsBetweenRetries="2" deadLetterQueue-ref="VM" doc:name="UntilSuccessful_Service">
<http:outbound-endpoint exchange-pattern="request-response" method="POST" doc:name="HTTP" address="http://localhost:1112/symbotic"/>
</until-successful>
</flow>
Even then getting the null payload. Kindly suggest is this is the way your were directing me. Please correct me if im wrong.
until-successful is an asynchronous processor. It does not return response from service call.
Success or failure are defined as:
If the child message processor throws an exception, this is a failure.
If the child message processor does not return a message (e.g. is a one-way endpoint), this is a success.
If a 'failure expression' (see below) has been configured, the return message is evaluated against this expression to determine failure or not.
Otherwise:
If the child message processor returns a message that contains an exception payload, this is a failure.
If the child message processor returns a message that does not contain an exception payload, this is a success.
http://www.mulesoft.org/documentation/display/current/Routing+Message+Processors#RoutingMessageProcessors-UntilSuccessful