I'm using the following XML in mule communication using jaxws-client inside http outbound flow (POJO is the output from outbound Jaxws Client).
for sure generating WS code using wsdl2java plugin in maven , the generated code has class for exception coming from WS the class is :
com.nsn.ossbss.charge_once.wsdl.entity.tis.wsdl._1.TisException
for sure http response is 500 when we got SOAPFault after the WS raised this exception
com.nsn.ossbss.charge_once.wsdl.entity.tis.wsdl._1.TisException
INFO 2012-11-08 11:08:08,008 [[cxf].TCP_C_L.receiver.02] org.mule.transport.http.HttpClientMessageDispatcher: Received a redirect, but followRedirects=false. Response code: 500 Server Error
ERROR 2012-11-08 11:08:13,008 [[cxf].TCP_C_L.receiver.02] org.mule.exception.CatchMessagingExceptionStrategy:
********************************************************************************
Message : error. Failed to route event via endpoint: org.mule.module.cxf.CxfOutboundMessageProcessor. Message payload is of type: PostMethod
Code : MULE_ERROR--2
--------------------------------------------------------------------------------
Exception stack is:
1. error (com.nsn.ossbss.charge_once.wsdl.entity.tis.wsdl._1.TisException)
sun.reflect.NativeConstructorAccessorImpl:-2 (null)
2. error. Failed to route event via endpoint: org.mule.module.cxf.CxfOutboundMessageProcessor. Message payload is of type: PostMethod (org.mule.api.transport.DispatchException)
org.mule.module.cxf.CxfOutboundMessageProcessor:148 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/transport/DispatchException.html)
--------------------------------------------------------------------------------
Root Exception stack trace:
com.nsn.ossbss.charge_once.wsdl.entity.tis.wsdl._1.TisException: error
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
+ 3 more (set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
********************************************************************************
INFO 2012-11-08 11:08:13,009 [[cxf].TCP_C_L.receiver.02] org.mule.api.processor.LoggerMessageProcessor: org.apache.commons.httpclient.methods.PostMethod#d02649
INFO 2012-11-08 11:08:13,010 [[cxf].TCP_C_L.receiver.02] org.mule.api.processor.LoggerMessageProcessor: org.apache.commons.httpclient.methods.PostMethod#d02649
I'm getting the above error when handeling excpetion using :
<catch-exception-strategy>
<logger message="#[payload]" level="INFO" doc:name="Logger" />
<transformer ref="ByteArrayToString" />
<append-string-transformer message="
" />
<logger message="#[payload]" level="INFO" doc:name="Logger" />
</catch-exception-strategy>
for sure I need to handle the exception same as apache camel , I need to specify to mule the exception and mule should not raised the above exception in the console as it would be handled by XML configuration .
the type of the incoming messages from jaxWs-client outbound is
org.apache.commons.httpclient.methods.PostMethod#d02649
How can i manage to make Mule ESB understand the WS exception , I tried this
and it didnt work as well .
Can you please advise .
in Fuse ESB i did it like this :
<onException>
<exception>com.nsn.ossbss.charge_once.wsdl.entity.tis.wsdl._1.TisException</exception>
<handled>
<constant>true</constant>
</handled>
<to uri="log:test" />
<setBody>
<simple>${exception.getFaultInfo}</simple>
</setBody>
<to uri="log:exception" />
<convertBodyTo type="com.nsn.ossbss.charge_once.wsdl.entity.tis.xsd._1.FaultMessage" />
<marshal ref="decExc" />
<convertBodyTo type="String" />
<bean ref="nulladd" />
</onException>
how can i make the same in Mule ESB .
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:vm="http://www.mulesoft.org/schema/mule/vm" xmlns:file="http://www.mulesoft.org/schema/mule/file"
xmlns:mulexml="http://www.mulesoft.org/schema/mule/xml" xmlns:tcp="http://www.mulesoft.org/schema/mule/tcp"
xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:http="http://www.mulesoft.org/schema/mule/http"
xmlns:cxf="http://www.mulesoft.org/schema/mule/cxf" xmlns:tracking="http://www.mulesoft.org/schema/mule/ee/tracking"
xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
xmlns:spring="http://www.springframework.org/schema/beans" xmlns:core="http://www.mulesoft.org/schema/mule/core"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="EE-3.3.0"
xmlns:script="http://www.mulesoft.org/schema/mule/scripting"
xsi:schemaLocation="
http://www.mulesoft.org/schema/mule/vm http://www.mulesoft.org/schema/mule/vm/current/mule-vm.xsd
http://www.mulesoft.org/schema/mule/file http://www.mulesoft.org/schema/mule/file/current/mule-file.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/scripting http://www.mulesoft.org/schema/mule/scripting/3.2/mule-scripting.xsd
http://www.mulesoft.org/schema/mule/tcp http://www.mulesoft.org/schema/mule/tcp/current/mule-tcp.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/cxf http://www.mulesoft.org/schema/mule/cxf/current/mule-cxf.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/ee/tracking http://www.mulesoft.org/schema/mule/ee/tracking/current/mule-tracking-ee.xsd ">
<spring:beans>
<spring:bean name="samlCallbackHandler"
class="com.mulesoft.mule.example.security.SAMLCallbackHandler" id="samlCallbackHandler" />
</spring:beans>
<sub-flow name="Jaxws" doc:name="Jaxws">
<cxf:jaxws-client operation="ExecuteCommand"
serviceClass="com.nsn.ossbss.charge_once.wsdl.entity.tis.wsdl._1.TisInterface"
doc:name="UsernameToken SOAP client">
<!-- <cxf:ws-security> <cxf:ws-config> <cxf:property key="action" value="UsernameToken
Timestamp" /> <cxf:property key="user" value="joe" /> <cxf:property key="passwordCallbackClass"
value="com.mulesoft.mule.example.security.PasswordCallback" /> <cxf:property
key="mustUnderstand" value="false" /> </cxf:ws-config> </cxf:ws-security> -->
</cxf:jaxws-client>
</sub-flow>
<sub-flow name="usernameToken1" doc:name="usernameToken1">
<!-- <cxf:jaxws-client operation="ExecuteCommand" serviceClass="com.nsn.ossbss.charge_once.wsdl.entity.tis.wsdl._1.TisInterface"
doc:name="UsernameToken SOAP client"> <cxf:ws-security> <cxf:ws-config> <cxf:property
key="action" value="UsernameToken Timestamp" /> <cxf:property key="user"
value="joe" /> <cxf:property key="passwordCallbackClass" value="com.mulesoft.mule.example.security.PasswordCallback"
/> <cxf:property key="mustUnderstand" value="false" /> </cxf:ws-config> </cxf:ws-security>
</cxf:jaxws-client> -->
<http:outbound-endpoint exchange-pattern="request-response"
host="localhost" port="8899" path="cxf/services"
doc:name="Invoke NSNusernameToken Web Service">
<cxf:jaxws-client operation="ExecuteCommand"
serviceClass="com.nsn.ossbss.charge_once.wsdl.entity.tis.wsdl._1.TisInterface"
doc:name="UsernameToken SOAP client">
<cxf:ws-security>
<cxf:ws-config>
<cxf:property key="action" value="UsernameToken Timestamp" />
<cxf:property key="user" value="joe" />
<cxf:property key="passwordCallbackClass"
value="com.mulesoft.mule.example.security.PasswordCallback" />
<cxf:property key="mustUnderstand" value="false" />
</cxf:ws-config>
</cxf:ws-security>
<cxf:inInterceptors />
<cxf:outInterceptors />
</cxf:jaxws-client>
</http:outbound-endpoint>
<logger message="#[payload]" level="INFO" doc:name="Logger" />
<mulexml:jaxb-object-to-xml-transformer
jaxbContext-ref="xmltoobj" />
<object-to-string-transformer />
<append-string-transformer message="
" />
<logger message="#[payload]" level="INFO" doc:name="Logger" />
</sub-flow>
<object-to-string-transformer name="ObjectToString" />
<byte-array-to-string-transformer
name="ByteArrayToString" />
<tcp:connector name="TCP_C_L" validateConnections="false"
receiveBufferSize="102400" sendBufferSize="102400" doc:name="TCP">
<tcp:xml-protocol />
</tcp:connector>
<mulexml:jaxb-context name="myJaxbContext"
packageNames="com.nsn.ossbss.charge_once.wsdl.entity.tis.xsd._1" />
<mulexml:jaxb-context name="xmltoobj"
packageNames="com.nsn.ossbss.charge_once.wsdl.entity.tis.xsd._1" />
<flow name="NSNServiceClient" doc:name="NSN IN Unified Client Service">
<tcp:inbound-endpoint host="localhost" port="51000"
connector-ref="TCP_C_L" />
<transformer ref="ByteArrayToString" />
<logger message="#[payload]" level="INFO" doc:name="Logger" />
<mulexml:jaxb-xml-to-object-transformer
jaxbContext-ref="myJaxbContext" />
<flow-ref name="usernameToken1" doc:name="usernameToken1" />
<logger message="#[payload]" level="INFO" doc:name="Logger" />
<!-- <default-exception-strategy> <choice>
<when evaluator="groovy" expression='payload.getException().getClass().getName().equals("com.nsn.ossbss.charge_once.wsdl.entity.tis.wsdl._1.TisException")'>
<logger message="#[payload]" level="INFO" doc:name="Logger" /> <object-to-string-transformer/>
<append-string-transformer message="
" /> <vm:outbound-endpoint
path="error.notification"/> </when> </choice> </default-exception-strategy> -->
<catch-exception-strategy>
<logger message="#[payload]" level="INFO" doc:name="Logger" />
<transformer ref="ByteArrayToString" />
<append-string-transformer message="
" />
<logger message="#[payload]" level="INFO" doc:name="Logger" />
</catch-exception-strategy>
<!-- <auto-transformer returnClass="com.nsn.ossbss.charge_once.wsdl.entity.tis.wsdl._1.TisException"/> -->
<!-- <custom-exception-strategy class="com.nsn.ossbss.charge_once.wsdl.entity.tis.wsdl._1.TisException">
<logger message="#[payload]" level="INFO" doc:name="Logger" /> </custom-exception-strategy> -->
</flow>
<flow name="SecurityClients" doc:name="SecurityClients">
<http:inbound-endpoint exchange-pattern="request-response"
host="localhost" port="63080" path="client" doc:name="HTTP Inbound Endpoint" />
<set-payload
value="#[message.inboundProperties['http.query.params']['name']]"
doc:name="Set payload with 'name' query param" />
<set-variable variableName="clientType"
value="#[message.inboundProperties['http.query.params']['clientType']]"
doc:name="Set clientType" />
<choice doc:name="Choice">
<when expression="#[clientType == 'unsecure']">
<processor-chain>
<flow-ref name="unsecure" doc:name="Invoke unsecure sub-flow" />
</processor-chain>
</when>
<!--<when expression="#[clientType == 'usernameToken']"> <processor-chain>
<flow-ref name="usernameToken1" doc:name="usernameToken1" /> </processor-chain>
</when> -->
<when expression="#[clientType == 'usernameTokenSigned']">
<processor-chain>
<flow-ref name="usernameTokenSigned" doc:name="Invoke usernameToken Signed sub-flow" />
</processor-chain>
</when>
<when expression="#[clientType == 'usernameTokenEncrypted']">
<processor-chain>
<flow-ref name="usernameTokenEncrypted" doc:name="Invoke usernameToken Encrypted sub-flow" />
</processor-chain>
</when>
<when expression="#[clientType == 'samlToken']">
<processor-chain>
<flow-ref name="samlToken" doc:name="Invoke samlToken sub-flow" />
</processor-chain>
</when>
<when expression="#[clientType == 'samlTokenSigned']">
<processor-chain>
<flow-ref name="samlTokenSigned" doc:name="Invoke samlToken Signed sub-flow" />
</processor-chain>
</when>
<otherwise>
<processor-chain>
<set-payload value="Client type is not supported"
doc:name="Client type is not supported" />
</processor-chain>
</otherwise>
</choice>
<set-property propertyName="Content-Type" value="text/plain"
doc:name="Set response Content-Type" />
<catch-exception-strategy doc:name="Catch Exception Strategy">
<set-payload value="There has been an Error processing the request"
doc:name="Set Payload" />
<set-property propertyName="Content-Type" value="text/plain"
doc:name="Set response Content-Type" />
</catch-exception-strategy>
</flow>
<sub-flow name="unsecure" doc:name="unsecure">
<cxf:jaxws-client operation="greet"
serviceClass="com.mulesoft.mule.example.security.Greeter" doc:name="Unsecure SOAP client"
doc:description="Unsecure SOAP client" />
<http:outbound-endpoint exchange-pattern="request-response"
host="localhost" port="63081" path="services/unsecure" doc:name="Invoke unsecure Web Service" />
</sub-flow>
<!-- <sub-flow name="usernameToken" doc:name="usernameToken"> <cxf:jaxws-client
operation="greet" serviceClass="com.mulesoft.mule.example.security.Greeter"
doc:name="UsernameToken SOAP client"> <cxf:ws-security> <cxf:ws-config> <cxf:property
key="action" value="UsernameToken Timestamp"/> <cxf:property key="user" value="joe"/>
<cxf:property key="passwordCallbackClass" value="com.mulesoft.mule.example.security.PasswordCallback"/>
</cxf:ws-config> </cxf:ws-security> </cxf:jaxws-client> <http:outbound-endpoint
exchange-pattern="request-response" host="localhost" port="63081" path="services/username"
doc:name="Invoke usernameToken Web Service"/> </sub-flow> -->
<sub-flow name="usernameTokenSigned" doc:name="usernameTokenSigned">
<cxf:jaxws-client operation="greet"
serviceClass="com.mulesoft.mule.example.security.Greeter" doc:name="UsernameToken Signed SOAP client">
<cxf:ws-security>
<cxf:ws-config>
<cxf:property key="action" value="UsernameToken Signature Timestamp" />
<cxf:property key="signaturePropFile" value="wssecurity.properties" />
<cxf:property key="user" value="joe" />
<cxf:property key="passwordCallbackClass"
value="com.mulesoft.mule.example.security.PasswordCallback" />
</cxf:ws-config>
</cxf:ws-security>
</cxf:jaxws-client>
<http:outbound-endpoint exchange-pattern="request-response"
host="localhost" port="63081" path="services/signed"
doc:name="Invoke usernameToken Signed Web Service" />
</sub-flow>
<sub-flow name="usernameTokenEncrypted" doc:name="usernameTokenEncrypted">
<cxf:jaxws-client operation="greet"
serviceClass="com.mulesoft.mule.example.security.Greeter" doc:name="UsernameToken Encrypted SOAP client">
<cxf:ws-security>
<cxf:ws-config>
<cxf:property key="action" value="UsernameToken Timestamp Encrypt" />
<cxf:property key="encryptionPropFile" value="wssecurity.properties" />
<cxf:property key="user" value="joe" />
<cxf:property key="encryptionUser" value="joe" />
<cxf:property key="passwordCallbackClass"
value="com.mulesoft.mule.example.security.PasswordCallback" />
</cxf:ws-config>
</cxf:ws-security>
</cxf:jaxws-client>
<http:outbound-endpoint exchange-pattern="request-response"
host="localhost" port="63081" path="services/encrypted"
doc:name="Invoke usernameToken Encrypted Web Service" />
</sub-flow>
<sub-flow name="samlToken" doc:name="samlToken">
<cxf:jaxws-client operation="greet"
serviceClass="com.mulesoft.mule.example.security.Greeter" doc:name="SAMLToken SOAP client">
<cxf:ws-security>
<cxf:ws-config>
<cxf:property key="action" value="SAMLTokenUnsigned Timestamp" />
<cxf:property key="samlPropFile" value="saml.properties" />
<cxf:property key="samlCallbackClass"
value="com.mulesoft.mule.example.security.SAMLCallbackHandler" />
</cxf:ws-config>
</cxf:ws-security>
</cxf:jaxws-client>
<http:outbound-endpoint exchange-pattern="request-response"
host="localhost" port="63081" path="services/saml" doc:name="Invoke SAMLToken Web Service" />
</sub-flow>
<sub-flow name="samlTokenSigned" doc:name="samlTokenSigned">
<cxf:jaxws-client operation="greet"
serviceClass="com.mulesoft.mule.example.security.Greeter" doc:name="SAMLToken Signed SOAP client">
<cxf:ws-security>
<cxf:ws-config>
<cxf:property key="action" value="SAMLTokenSigned" />
<cxf:property key="samlPropFile" value="saml.properties" />
<cxf:property key="signatureKeyIdentifier" value="DirectReference" />
<cxf:property key="user" value="joe" />
<cxf:property key="passwordCallbackClass"
value="com.mulesoft.mule.example.security.PasswordCallback" />
<cxf:property key="samlCallbackClass"
value="com.mulesoft.mule.example.security.SAMLCallbackHandler" />
</cxf:ws-config>
</cxf:ws-security>
</cxf:jaxws-client>
<http:outbound-endpoint exchange-pattern="request-response"
host="localhost" port="63081" path="services/signedsaml"
doc:name="Invoke SAMLToken Signed Web Service" />
</sub-flow>
</mule>
The first sub flow usernameToken1 is calling the Web service which i deployed on apache camel , I just mentioned in the question above the exception class which has been raised.
Kindly let me know your feedback,
The problem you are having is that by the time the Payload reaches the exception strategy block, the Message has already been consumed by the jaxws-client and you cannot get hold of it anymore.
What you could do is have the jaxws client outside of the outbound endpoint (right before). After the outbound endpoint you'll have the Soap Message. You can check if it was an exception or not, merely by checking the http status. If the status is an error, you can transform the message to string and store it in a variable. Once the message reaches the client on the way back, it's going to interpret the Soap message and throw the exception that it's going to be handled by the exception strategy block. Inside the exception you can read the variable where you are storing the Soap Fault and do whatever you want with it.
I know it is a very cumbersome solution, but it's the only one I can think of. The problem as I said before, is that HTTP receives a stream back from the service, and that stream is then consumed by the jaxws client before unmarshalling and throwing the exception. The only way to preserve the Soap Fault would be if Mule serializes the input every time, which can be very expensive.
HTH,
Eva
Related
I'm trying to read a value inside a JSON string.
The payload from getValue is as simple as :
{ 'result': 'new_value' }
When I try to log the result it prints null
My code is:
<enricher target="#[flowVars.new_value]" source="#[json:result]">
<flow-ref name="getValue" />
</enricher>
<logger doc:name="Logger" level="INFO"
message="new value #[flowVars.new_value]" />
<flow name="getValue">
<http:request config-ref="http-request-tts" path="get_value" method="POST">
</http:request>
<!-- Here the payload is of type org.glassfish.grizzly.utils.BufferInputStream -->
<object-to-string-transformer/>
<json:object-to-json-transformer />
</flow>
Remove <object-to-string-transformer/> after http:request and
You need to do the following in enricher:-
<enricher target="#[flowVars.new_value]" source="#[message.payload.result]" doc:name="Message Enricher">
<processor-chain doc:name="Processor Chain">
<flow-ref name="getValue" doc:name="Flow Reference"/>
<json:json-to-object-transformer returnClass="java.lang.Object" doc:name="JSON to Object" />
</processor-chain>
</enricher>
<logger doc:name="Logger" level="INFO" message="authorization_token #[flowVars.new_value]" />
But remember, your Json should be in the format :- { "result": "new_value"} and not { 'result': 'new_value' }
How do exception can be rethrow from catch-exception-strategy in mule.
Tried with below flows and after an exception from "flowdemo" errorhandling, it doesn't go to errorhandling of mdemoflow. it executes logger that is place after flow-ref.
<mule ....>
<sub-flow name="exceFlow">
<logger level="ERROR" doc:name="Logger"/>
<expression-component doc:name="Expression"><![CDATA[throw new java.lang.IllegalArgumentException('bad arg');]]></expression-component>
<validation:is-true expression="false" doc:name="Validation"/>
<scripting:component doc:name="Script">
<scripting:script engine="Groovy"><![CDATA[throw new java.lang.IllegalArgumentException('bad arg')]]></scripting:script>
</scripting:component>
<logger level="INFO" doc:name="Logger"/>
</sub-flow>
<flow name="flowdemo" processingStrategy="synchronous">
<expression-component doc:name="Expression"><![CDATA[flowVars.dummy = flowVars.fake.test]]></expression-component>
<catch-exception-strategy doc:name="Catch Exception Strategy" >
<flow-ref name="exceFlow" doc:name="Flow Reference"/>
</catch-exception-strategy>
</flow>
<flow name="mdemoFlow" processingStrategy="synchronous">
<poll doc:name="Poll">
<fixed-frequency-scheduler frequency="3" timeUnit="MINUTES"/>
<logger level="INFO" doc:name="Logger"/>
</poll>
<flow-ref name="flowdemo" doc:name="flowdemo"/>
<logger level="INFO" doc:name="Logger"/>
<catch-exception-strategy doc:name="Catch Exception Strategy">
<logger message="test logging in error" level="ERROR" doc:name="Logger"/>
<logger level="INFO" doc:name="Logger"/>
</catch-exception-strategy>
</flow>
</mule>
flowdemo which is flow ( Not a subflow) and has its own catch Exception Stratergy(So it is being handled by the demo flow itself). Thread started from main flow (mdemoFlow) which is calling other flow Via flowRef hence it is back to the mainFlow to complete the thread which is expected(Irrespective of flow processing strategy). If you want to handled all the exception in the main flow itself. Please use the below config ( Make the flowdemo as subflow), so by default any exception happen in its associated subflow will be back to its main flow to handle the same.
<sub-flow name="flowdemo" >
<expression-component doc:name="Expression"><![CDATA[flowVars.dummy = flowVars.fake.test]]></expression-component>
</sub-flow>
<flow name="mdemoFlow" processingStrategy="synchronous">
<poll doc:name="Poll">
<fixed-frequency-scheduler frequency="3" timeUnit="MINUTES"/>
<logger level="INFO" doc:name="Logger"/>
</poll>
<flow-ref name="flowdemo" doc:name="flowdemo"/>
<logger level="INFO" doc:name="Logger" message="***final logger***"/>
<catch-exception-strategy doc:name="Catch Exception Strategy">
<logger message="test logging in error" level="ERROR" doc:name="Logger"/>
<logger level="INFO" doc:name="Logger"/>
<flow-ref name="exceFlow" doc:name="Flow Reference"/>
</catch-exception-strategy>
</flow>
<sub-flow name="exceFlow">
<logger level="ERROR" doc:name="Logger"/>
<logger level="INFO" doc:name="Logger"/>
</sub-flow>
To make Exception strategy as Global. You can use global exception strategy and call the same via reference Exception strategy. Please refer the link for more details https://docs.mulesoft.com/mule-user-guide/v/3.7/reference-exception-strategy
I am using MULE ESB and have a flow which is designed to pull all the results out of the Mysql Database and place all the results in one JSON file. However I am gettign the results as separate JSON files, not one JSON file (which is the desired outcome)
Here is my config file
<context:property-placeholder location="classpath:mysql.properties,classpath:smtp.properties" />
<smtp:connector name="emailConnector" fromAddress="${smtp.from}" subject="${smtp.subject}" doc:name="SMTP" validateConnections="true"/>
<jdbc-ee:connector name="jdbcConnector" dataSource-ref="MySQL_Data_Source" validateConnections="false" queryTimeout="10" pollingFrequency="10000" doc:name="JDBC">
<jdbc-ee:query key="Users" value="SELECT * FROM test ORDER BY id ASC"></jdbc-ee:query>
</jdbc-ee:connector>
<jdbc-ee:mysql-data-source name="MySQL_Data_Source" user="${mysql.user}" password="${mysql.password}" url="${mysql.url}" transactionIsolation="UNSPECIFIED" doc:name="MySQL Data Source"></jdbc-ee:mysql-data-source>
<flow name="flows1Flow1" >
<jdbc-ee:inbound-endpoint queryKey="Users" connector-ref="jdbcConnector" doc:name="JDBC"></jdbc-ee:inbound-endpoint>
<json:object-to-json-transformer doc:name="Object to JSON"/>
<file:outbound-endpoint path="C:\Users\IEUser\Desktop\New folder" doc:name="File" responseTimeout="10000"></file:outbound-endpoint>
</flow>
What version of Mule are you using? the jdbc connector you are using is deprecated in 3.5+. I was able to get the result you are expecting using the config below in 3.7.1:
<db:mysql-config name="MySQL_Configuration" host="localhost"
port="" user="" database="test" pass="" doc:name="MySQL Configuration" />
<flow name="flows1Flow1">
<poll doc:name="Poll">
<db:select config-ref="MySQL_Configuration" doc:name="Database">
<db:parameterized-query><![CDATA[SELECT * FROM test.people]]></db:parameterized-query>
</db:select>
</poll>
<json:object-to-json-transformer
doc:name="Object to JSON" />
<logger level="ERROR" message="#[payload]" doc:name="Logger" />
<file:outbound-endpoint path="./people"
doc:name="File" responseTimeout="10000" />
</flow>
HTH
EDIT: Simplified question.
Why on earth, the file written is garbage (binary serilized data) instead of the payload that was set in the Groovy component? This only happens if there is an "All" Flow component.
Flow:
XML:
<file:connector name="OutputFile" autoDelete="true" streaming="true" validateConnections="true" doc:name="File" writeToDirectory="#{systemProperties['user.home']}"/>
<flow name="AllProblemFlow1" doc:name="AllProblemFlow1">
<vm:inbound-endpoint exchange-pattern="one-way" path="in" doc:name="VM"/>
<all doc:name="All">
<processor-chain>
<scripting:component doc:name="Groovy">
<scripting:script engine="Groovy">
<scripting:text><![CDATA[return payload + 1]]></scripting:text>
</scripting:script>
</scripting:component>
</processor-chain>
<processor-chain>
<scripting:component doc:name="Groovy">
<scripting:script engine="Groovy">
<scripting:text><![CDATA[return payload + 2]]></scripting:text>
</scripting:script>
</scripting:component>
</processor-chain>
</all>
<logger message="All payload: #[payload]" level="INFO" doc:name="Logger"/>
<scripting:component doc:name="Groovy">
<scripting:script engine="Groovy">
<scripting:text><![CDATA[return "new payload"]]></scripting:text>
</scripting:script>
</scripting:component>
<file:outbound-endpoint responseTimeout="10000" connector-ref="OutputFile" doc:name="File" outputPattern="output.txt" path="#{systemProperties['user.home']}"/>
</flow>
This is very tricky: the all message processor changes the very nature of the in-flight Mule message from a MuleMessage to a MuleMessageCollection. Changing the payload on a MuleMessageCollection is basically ineffective.
You need to forcefully replace the current MuleMessageCollection with a brand new MuleMessage. Use the following code for your last Groovy component:
<scripting:text><![CDATA[
return new org.mule.DefaultMuleMessage("new payload", muleContext)
]]></scripting:text>
I have a Mule 3.3.0 flow which splits a file into records. I need to execute an action (stored procedure) AFTER ALL records have finished processing.
The problem is that sometimes the action gets executed before all records have been processed by Mule. I think this is due to the fact that Mule process stuff in parallel, which is great, so sometimes the final action gets called too early.
If I set the flow as synchronous things appear to work, but I'm not taking advantage of parallel execution.
I think I could also use a Foreach scope (haven't tried) but I guess that stuff will still not be parallelized.
Is there a way to "wait" until all records finish processing?
I'm attaching a very simple flow which exhibits this behaviour. If you run it you will see that the loggers don't print stuff in order. Actually, the "DONE" message gets logged before the rest.
The flow processes a simple csv file auntil it matches a field with value "end". There is a choice component which loggs "DONE" when such field is found. The rest of the fields simply get logged.
Any help will be greatly appreciated.
Flow:
Flow xml
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:scripting="http://www.mulesoft.org/schema/mule/scripting"
xmlns:vm="http://www.mulesoft.org/schema/mule/vm" xmlns:file="http://www.mulesoft.org/schema/mule/file"
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="CE-3.3.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.mulesoft.org/schema/mule/vm http://www.mulesoft.org/schema/mule/vm/current/mule-vm.xsd
http://www.mulesoft.org/schema/mule/file http://www.mulesoft.org/schema/mule/file/current/mule-file.xsd
http://www.mulesoft.org/schema/mule/scripting http://www.mulesoft.org/schema/mule/scripting/current/mule-scripting.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 ">
<file:connector name="inputFileConnector" autoDelete="true"
streaming="false" validateConnections="true" doc:name="File" fileAge="60000"
readFromDirectory="#{systemProperties['user.home']}" />
<flow name="flow1" doc:name="flow1" processingStrategy="synchronous">
<file:inbound-endpoint path="#{systemProperties['user.home']}"
responseTimeout="10000" doc:name="Input File" fileAge="100"
connector-ref="inputFileConnector">
<file:filename-regex-filter pattern="input.csv"
caseSensitive="false" />
</file:inbound-endpoint>
<byte-array-to-string-transformer
doc:name="Byte Array to String" />
<scripting:component doc:name="Groovy">
<scripting:script engine="Groovy">
<scripting:text><![CDATA[return payload.split('\n');]]></scripting:text>
</scripting:script>
</scripting:component>
<collection-splitter doc:name="Collection Splitter" />
<choice doc:name="Choice">
<when expression="#[groovy:payload != 'end']">
<processor-chain>
<logger message="." level="INFO" doc:name="Process"/>
<vm:outbound-endpoint path="toFlow2" doc:name="VM"/>
</processor-chain>
</when>
<otherwise>
<processor-chain>
<logger message="|||| DONE" level="INFO" doc:name="DONE"/>
</processor-chain>
</otherwise>
</choice>
</flow>
<flow name="flow2" doc:name="flow2" >
<vm:inbound-endpoint path="toFlow2" doc:name="VM"/>
<scripting:component doc:name="Groovy">
<scripting:script engine="Groovy">
<scripting:text><![CDATA[return payload.split(',');]]></scripting:text>
</scripting:script>
</scripting:component>
<collection-splitter doc:name="Collection Splitter" />
<logger message="|||||| #[payload]" level="INFO" doc:name="Logger"/>
<vm:outbound-endpoint path="toFlow3" doc:name="VM"/>
</flow>
One option is to use a collection-aggregator to act as an accumulator, blocking the final flow action until all the messages have been processed. The trick is that the collection-splitters will set up a correlation group size that is only good for either the number of lines in the file or the number of columns in the file. But we want to accumulate until all columns of all lines have been processed. The solution consists in computing first this value (ie total number of expected messages) and overriding whatever correlation group size had been calculated the collection-splitters with the total value.
Here is how I've done this (you'll note that I replaced all Groovy snippets with more Mule-3-esque MEL expressions):
<file:connector name="inputFileConnector" autoDelete="true"
streaming="false" validateConnections="true" fileAge="60000"
readFromDirectory="#{systemProperties['user.home']}" />
<flow name="flow1" processingStrategy="synchronous">
<file:inbound-endpoint path="#{systemProperties['user.home']}"
responseTimeout="10000" fileAge="100"
connector-ref="inputFileConnector">
<file:filename-regex-filter pattern="input.csv"
caseSensitive="false" />
</file:inbound-endpoint>
<byte-array-to-string-transformer />
<set-session-variable variableName="expectedMessageCount"
value="#[org.mule.util.StringUtils.countMatches(message.payload, '\n') + org.mule.util.StringUtils.countMatches(message.payload, ',') - 1]" />
<expression-transformer expression="#[message.payload.split('\n')]" />
<collection-splitter enableCorrelation="IF_NOT_SET" />
<set-property propertyName="MULE_CORRELATION_GROUP_SIZE"
value="#[sessionVars.expectedMessageCount]" />
<choice>
<when expression="#[message.payload != 'end']">
<processor-chain>
<logger message="." level="INFO" />
<vm:outbound-endpoint path="toFlow2" />
</processor-chain>
</when>
<otherwise>
<processor-chain>
<logger message="|||| END" level="INFO" />
</processor-chain>
</otherwise>
</choice>
</flow>
<flow name="flow2">
<vm:inbound-endpoint path="toFlow2"/>
<expression-transformer expression="#[message.payload.split(',')]" />
<collection-splitter />
<set-property propertyName="MULE_CORRELATION_GROUP_SIZE"
value="#[sessionVars.expectedMessageCount]" />
<logger message="|||||| #[message.payload]" level="INFO"/>
<vm:outbound-endpoint path="toFinalizer" />
<vm:outbound-endpoint path="toFlow3" />
</flow>
<flow name="finalizer">
<vm:inbound-endpoint path="toFinalizer" />
<collection-aggregator />
<logger message="|||| DONE" level="INFO" />
</flow>
NB. Alternatively, if using a collection-aggregator is an issue because it uses too much memory, you could use an expression component to decrement sessionVars.expectedMessageCount and filter to let a message hit the final message processor when the counter is back to 0.