Mule ESB 3.3 How to start transactional flows concurrently - asynchronous

I would like to process set of messages concurrently, but I can't manage to make them transacional unless I set the VM to request-response... in which case the processing is not concurrent.
Mule documentation states that "Mule transactions are configured on synchronous endpoints", but I don't quite understand this restriction.
It is clear that inside a flow that you want to be transactional one should not spawn asynch flows, but it is not clear (to me) why one can't start (from a non tx main flow) any number of asynchronous flows each being transactional.
In other words why does this work fine:
but if I change the VM's to "one-way" it fails with:
org.mule.transaction.IllegalTransactionStateException: Can only bind "javax.sql.DataSource/java.sql.Connection" type resources
Is there a way around this?
XML for the flow:
<?xml version="1.0" encoding="UTF-8"?>
<mule>
<spring:beans>
<spring:bean id="dataSource" name="dataSource" class="org.enhydra.jdbc.standard.StandardDataSource" destroy-method="shutdown">
<spring:property name="driverName" value="org.h2.Driver" />
<spring:property name="url" value="jdbc:h2:tcp://localhost/~/mule" />
<spring:property name="user" value="sa" />
<spring:property name="password">
<spring:value></spring:value>
</spring:property>
</spring:bean>
<spring:bean id="transactionFactory" name="transactionFactory" class="org.mule.transport.jdbc.JdbcTransactionFactory" />
</spring:beans>
<jdbc:connector name="dbConnector" dataSource-ref="dataSource" validateConnections="true" queryTimeout="-1" pollingFrequency="0" doc:name="Database" />
<flow name="triggerFlow" doc:name="triggerFlow">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" doc:name="HTTP" />
<set-payload value="#[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]" doc:name="[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"/>
<collection-splitter doc:name="Collection Splitter"/>
<vm:outbound-endpoint exchange-pattern="request-response" path="flow" doc:name="flow" />
</flow>
<flow name="flow" doc:name="flow">
<vm:inbound-endpoint exchange-pattern="request-response" path="flow" doc:name="flow">
<custom-transaction factory-ref="transactionFactory" action="ALWAYS_BEGIN" timeout="10" />
</vm:inbound-endpoint>
<logger message="#[payload]" level="INFO" doc:name="Logger"/>
<jdbc:outbound-endpoint exchange-pattern="request-response" queryKey="insert" queryTimeout="-1" connector-ref="dbConnector" doc:name="Insert 1">
<jdbc:transaction action="ALWAYS_JOIN" />
<jdbc:query key="insert" value="insert into test values (#[payload], 'Test 1')" />
</jdbc:outbound-endpoint>
<jdbc:outbound-endpoint exchange-pattern="request-response" queryKey="insert2" queryTimeout="-1" connector-ref="dbConnector" doc:name="Insert 2">
<jdbc:transaction action="ALWAYS_JOIN" />
<jdbc:query key="insert2" value="insert into test values (#[payload + 10], 'Test 2')" />
</jdbc:outbound-endpoint>
</flow>
</mule>
Thanks in advance.

Mule documentation states that "Mule transactions are configured on synchronous endpoints", but I don't quite understand this restriction.
This restriction is due to the fact that, in Mule like in Spring, and more generally in Java, transactions are thread-bound. With asynchronous flows, multiple threads are involved, hence the transaction-thread association can't be maintained.
So no, you can't split/fork/parallelize/asynchronous process messages and also have transactions in Mule.
org.mule.transaction.IllegalTransactionStateException: Can only bind "javax.sql.DataSource/java.sql.Connection" type resources
But this is unrelated to the first question IMO: this is because you forcefully, via a custom-transaction, try to enrol a VM endpoint in a JDBC transaction. This can not work. Use an XA transaction if you want to enrol heterogeneous resources.
EDIT: From what you've said in the comments, you do not want to enrol the VM endpoint in the transaction, so just enrol the JDBC endpoints as in here:
<transactional action="ALWAYS_BEGIN">
<jdbc:outbound-endpoint exchange-pattern="request-response"
queryKey="insert" queryTimeout="-1" connector-ref="dbConnector"
doc:name="insert into test values (1, 'Test 1')">
<jdbc:transaction action="ALWAYS_JOIN" />
<jdbc:query key="insert"
value="insert into test values (1, 'Test 1')" />
</jdbc:outbound-endpoint>
<jdbc:outbound-endpoint exchange-pattern="request-response"
queryKey="insert2" queryTimeout="-1" connector-ref="dbConnector"
doc:name="insert into test values (2, 'Test 2')">
<jdbc:transaction action="ALWAYS_JOIN" />
<jdbc:query key="insert2"
value="insert into test values (2, 'Test 2')" />
</jdbc:outbound-endpoint>
</transactional>
This works fine with a one-way inbound endpoint.

I managed to make it work. I had to add an intermediate async flow wich invokes the sync/tx flow:
I think this is ugly and unnecesary and that it would be perfectly ok to invoke it as the original post, but for reasons than are beyond me Mule makes you jump through hoops for this.
Following is the flow's XML:
<?xml version="1.0" encoding="UTF-8"?>
<mule>
<spring:beans>
<spring:bean id="dataSource" name="dataSource" class="org.enhydra.jdbc.standard.StandardDataSource" destroy-method="shutdown">
<spring:property name="driverName" value="org.h2.Driver" />
<spring:property name="url" value="jdbc:h2:tcp://localhost/~/mule" />
<spring:property name="user" value="sa" />
<spring:property name="password">
<spring:value></spring:value>
</spring:property>
</spring:bean>
<spring:bean id="transactionFactory" name="transactionFactory" class="org.mule.transport.jdbc.JdbcTransactionFactory" />
</spring:beans>
<jdbc:connector name="dbConnector" dataSource-ref="dataSource" validateConnections="true" queryTimeout="-1" pollingFrequency="0" doc:name="Database" />
<flow name="triggerFlow" doc:name="triggerFlow">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" doc:name="HTTP" />
<set-payload value="#[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]" doc:name="[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"/>
<collection-splitter doc:name="Collection Splitter"/>
<vm:outbound-endpoint exchange-pattern="one-way" path="async" doc:name="async" />
</flow>
<flow name="simpletransactionFlow1" doc:name="simpletransactionFlow1">
<vm:inbound-endpoint exchange-pattern="one-way" path="async" doc:name="async"/>
<vm:outbound-endpoint exchange-pattern="request-response" path="flow" doc:name="flow"/>
</flow>
<flow name="flow" doc:name="flow">
<vm:inbound-endpoint exchange-pattern="request-response" path="flow" doc:name="flow">
<custom-transaction factory-ref="transactionFactory" action="ALWAYS_BEGIN" timeout="10" />
</vm:inbound-endpoint>
<logger message="#[groovy:Thread.currentThread().getName()], payload=#[payload]" level="INFO" doc:name="Logger"/>
<jdbc:outbound-endpoint exchange-pattern="request-response" queryKey="insert" queryTimeout="-1" connector-ref="dbConnector" doc:name="Insert 1">
<jdbc:transaction action="ALWAYS_JOIN" />
<jdbc:query key="insert" value="insert into test values (#[payload], 'Test 1')" />
</jdbc:outbound-endpoint>
<jdbc:outbound-endpoint exchange-pattern="request-response" queryKey="insert2" queryTimeout="-1" connector-ref="dbConnector" doc:name="Insert 2">
<jdbc:transaction action="ALWAYS_JOIN" />
<jdbc:query key="insert2" value="insert into test values (#[payload + 10], 'Test 2')" />
</jdbc:outbound-endpoint>
</flow>
</mule>

This is discussed in the Mule documentation. It is a little more cumbersome that it needs to be perhaps, but it's not too bad, and only actually requires one VM Transport, not two:
I changed it because I wanted to use TCP instead of HTTP, but it's basically the same example.
The first flow receives untransacted TCP, does something with it (just a Byte Array To String here, but possibly you'd have validation or something), pushes the input to the VM Connector, then echos the input back to the TCP stream. Returning after the VM Connector guarantees that the TCP source that it can let go of its message, if it's doing a little low-level guaranteed delivery.
The VM Connector is one-way, and has a persistent store connected to it so it can't lose the message. This shows an error in Mule Studio 3.5, but it works fine.
Then the middle flow takes over, and contains a transaction so the VM Connector won't let go of the message unless the business logic subflow completes successfully.
Finally the subflow runs; currently just Thread.sleep()ing for 5 seconds so I can see it's all working. Telnetting in has an instant echo back to the Telnet console, then five seconds later another echo.
Hope that helps! I've only spent a couple of hours with Mule altogether, but this seems to be correct.

Related

Migration of code Mule 3 to Mule 4 and 'rest-router' is not supported in Mule 4

I have one application which is Mule 3, now I need to migrate it into Mule 4.
I implemented and changed some code but it through exceptions that tag not supported i.e 'rest-router' is not supported.
<rest-router:router templateUri="${igate.url}">
<!--Migration ERROR: The migration of 'rest-router' is not supported.-->
<!-- For more information refer to:-->
<!-- * https://docs.mulesoft.com/mule-runtime/4.1/migration-connectors>--
<!-- * https://beta.docs.stgx.mulesoft.com/beta-mule-migration-tool/mule-runtime/4.1/migration-tool.html#unsupported_connectors-->
<rest-router:post>
<ee:transform xmlns:ee="http://www.mulesoft.org/schema/mule/ee/core" doc:name="JSON to Object">
<ee:message>
<ee:set-payload>%dw 2.0 output application/java --- payload as Object { class: 'com.ifi.igate.model.Transaction'}</ee:set-payload>
</ee:message>
</ee:transform>
<flow-ref name="igate-object-flow" doc:name="igate-object-flow" />
<ee:transform xmlns:ee="http://www.mulesoft.org/schema/mule/ee/core" doc:name="Object to JSON" mimeType="application/json">
<ee:message>
<ee:set-payload>%dw 2.0 output application/json --- payload</ee:set-payload>
</ee:message>
</ee:transform>
</rest-router:post>
</rest-router:router>
Full XML file in Mule 3 which we need to migrate on Mule 4 -
<spring:beans>
<spring:bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<spring:property name="ignoreUnresolvablePlaceholders" value="true"/>
<spring:property name="location" value="igate.properties"/>
</spring:bean>
<spring:bean id="validation" class="com.ifi.igate.integration.iclient.ValidationTransformer">
<spring:property name="transactionTypes">
<spring:list>
<spring:value>INQ-REQ</spring:value>
<spring:value>DEP-REQ</spring:value>
<spring:value>WIT-REQ</spring:value>
</spring:list>
</spring:property>
</spring:bean>
<spring:bean id="iGateStub" class="com.ifi.igate.stub.IGateStub">
<spring:property name="handlers">
<spring:map>
<spring:entry key="INQ-REQ">
<spring:bean class="com.ifi.igate.stub.handlers.InqHandler"/>
</spring:entry>
<spring:entry key="WIT-REQ">
<spring:bean class="com.ifi.igate.stub.handlers.WitHandler"/>
</spring:entry>
<spring:entry key="DEP-REQ">
<spring:bean class="com.ifi.igate.stub.handlers.DepHandler"/>
</spring:entry>
</spring:map>
</spring:property>
</spring:bean>
</spring:beans>
<rest-router:config/>
<http:connector name="httpConnector" doc:name="HTTP\HTTPS">
<receiver-threading-profile maxThreadsActive="10" />
</http:connector>
<flow name="igate-json-flow" doc:name="igate-json-flow">
<http:inbound-endpoint exchange-pattern="request-response" host="${igate.host}" port="${igate.port}" doc:name="HTTP"/>
<rest-router:router templateUri="${igate.url}">
<rest-router:post>
<json:json-to-object-transformer xmlns:json="http://www.mulesoft.org/schema/mule/json" returnClass="com.ifi.igate.model.Transaction" doc:name="JSON to Object"></json:json-to-object-transformer>
<flow-ref name="igate-object-flow" doc:name="igate-object-flow"/>
<json:object-to-json-transformer xmlns:json="http://www.mulesoft.org/schema/mule/json" doc:name="Object to JSON" mimeType="application/json"></json:object-to-json-transformer>
</rest-router:post>
</rest-router:router>
<rest-router:router templateUri="${igate-stub.url}">
<rest-router:post>
<json:json-to-object-transformer xmlns:json="http://www.mulesoft.org/schema/mule/json" returnClass="com.ifi.igate.model.Transaction" doc:name="JSON to Object"/>
<component doc:name="IGateStub">
<spring-object bean="iGateStub"/>
</component>
<json:object-to-json-transformer xmlns:json="http://www.mulesoft.org/schema/mule/json" doc:name="Object to JSON" mimeType="application/json"/>
</rest-router:post>
</rest-router:router>
</flow>
<sub-flow name="igate-object-flow" doc:name="igate-object-flow">
<transformer ref="validation"/>
<choice>
<when expression="#[message.payload.trxstatus == 0]">
<logger message="#[message.payload.trxreason]" level="ERROR" doc:name="Logger"/>
</when>
<otherwise>
<set-variable variableName="request" value="#[message.payload]" doc:name="save request"/>
<flow-ref name="promotions-flow" doc:name="Promotions Flow"/>
<flow-ref name="ifi-membership-flow" doc:name="Accumulate Spending"/>
<!-- logger message="Before backend" level="ERROR" doc:name="Logger"/-->
<flow-ref name="rewards-flow" doc:name="Rewards Flow"/>
<choice>
<when expression="#[message.payload.values['PTS']>0 || message.payload.trxtype=='INQ-REQ']">
<flow-ref name="${igate.membership}-membership-flow" doc:name="External Membership Flow"/>
</when>
<otherwise>
<vm:outbound-endpoint exchange-pattern="request-response" path="membership/ifi" />
</otherwise>
</choice>
<!-- logger message="After backend" level="ERROR" doc:name="Logger"/-->
<flow-ref name="promotions-flow" doc:name="Promotions Flow"/>
<flow-ref name="rewards-flow" doc:name="Rewards Flow"/>
<flow-ref name="ifi-membership-flow" doc:name="Manage balances"/>
<flow-ref name="pricing-flow" doc:name="Pricing Flow"/>
</otherwise>
</choice>
</sub-flow>
</mule>
'rest-router' is not supported in Mule 4 only need replacement for that tag or How I can migrate it into Mule 4.
rest-router seems to be an unsupported and unmaintained (last commit is from 2012) module for Mule 3. You best bet is to migrate from scratch and use APIKit instead. You will need to write a RAML specification for your API and Studio will create all the needed scaffolding from it.

mule 3.5 follow redirects on outbound endpoint

I have the simple flows as following. When we hit one flow, it hits another flow and gets http.status 302 and Location , which means it must redirect to the location in Location header. But it is throwing exception.
<flow name="httpconnectorFlowRedirection">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="9876" path="redirect" connector-ref="NoSessionEncodingConnector" doc:name="HTTP"/>
<http:outbound-endpoint exchange-pattern="request-response" host="localhost" port="9876" method="POST" doc:name="HTTP" path="temp" connector-ref="NoSessionEncodingConnector" contentType="text/plain"
followRedirects="true" />
<logger message="#[payload]" level="INFO" doc:name="Logger"/>
</flow>
<flow name="temp_flow">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="9876" path="temp" connector-ref="NoSessionEncodingConnector" doc:name="HTTP" />
<logger message="in temp flow" level="INFO" doc:name="Logger"/>
<set-property propertyName="http.status" value="307" doc:name="Property" />
<set-property propertyName="Location" value="http://localhost:9876/samplehttp" doc:name="Property" />
</flow>
Error I am getting is as follows
org.mule.exception.DefaultMessagingExceptionStrategy:
********************************************************************************
Message : Failed to route event via endpoint: DefaultOutboundEndpoint{endpointUri=http://localhost:9876/temp, connector=HttpConnector
{
name=NoSessionEncodingConnector
lifecycle=start
this=14c5f0c
numberOfConcurrentTransactedReceivers=4
createMultipleTransactedReceivers=true
connected=true
supportedProtocols=[http]
serviceOverrides=
session.handler=org.mule.session.NullSessionHandler
}
, name='endpoint.http.localhost.9876.temp', mep=REQUEST_RESPONSE, properties={exceptionOnMessageError=true, http.method=POST, followRedirects=true, Content-Type=text/plain}, transactionConfig=Transaction{factory=null, action=INDIFFERENT, timeout=0}, deleteUnacceptedMessages=false, initialState=started, responseTimeout=10000, endpointEncoding=UTF-8, disableTransportTransformer=false}. Message payload is of type: PostMethod
Type : org.mule.api.transport.DispatchException
Code : MULE_ERROR--2
JavaDoc : http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/transport/Dispat chException.html
Payload : org.apache.commons.httpclient.methods.PostMethod#14efe2e
********************************************************************************
I am getting this error only when follow redirects set to true on outbound endpoint
I am using mule 3.5.
I got the answer. I need to use GET reqeust for successful redirection.
But if I use http listeners(since mule 3.6), I am able to redirect even for POST requests. Consider the following example.
<http:listener-config name="GlobalHTTPConnector" host="localhost" port="9876" doc:name="HTTP Listener Configuration" basePath="mulelearning"/>
<flow name="redirection-flow">
<http:listener config-ref="GlobalHTTPConnector" path="/requestredir" doc:name="HTTP"/>
<!--
When followRedirects is set to true, when http.status from called service is redirection(eg:301), it redirects to new location.
In this case /redFlow1 sends a redirection code 301 and location header. Hence it redirects to /redFlow2 (see the flows below) and gives us the response 'payload from red-flow2'
-->
<http:request config-ref="HTTP_Request_Configuration" path="/redFlow1" method="POST" followRedirects="true" doc:name="HTTP" />
</flow>
<flow name="red-ser1">
<http:listener config-ref="GlobalHTTPConnector" path="/redFlow1" doc:name="HTTP"/>
<logger level="INFO" doc:name="Logger" message="I am in red-flow1"/>
<set-payload value="payload from red-flow1" />
<set-property propertyName="http.status" value="301" doc:name="Property" />
<set-property propertyName="Location" value="http://localhost:9876/mulelearning/redFlow2" doc:name="Property" />
</flow>
<flow name="red-ser2">
<http:listener config-ref="GlobalHTTPConnector" path="/redFlow2" doc:name="HTTP"/>
<set-payload value="payload from red-flow2" />
<logger level="INFO" doc:name="Logger" message="I am in red-flow2"/>
</flow>

Using Records Across Flows in Mule 3.4

I want to select records from a database and use them across different flows in mule.
My approach is to get the records using a Spring bean and pass it to a hashmap then return the hashmap and save it in a session variable.
Currently getting this error:
Message : Execution of the expression "message.payload.getServiceCodes()" failed. (org.mule.api.expression.ExpressionRuntimeException). Message payload is of type: HashMap
Code : MULE_ERROR--2
Its there a better approach? Or what I'm I doing wrong?
My Configuration XML
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:tracking="http://www.mulesoft.org/schema/mule/ee/tracking" xmlns:quartz="http://www.mulesoft.org/schema/mule/quartz" xmlns:jdbc-ee="http://www.mulesoft.org/schema/mule/ee/jdbc" xmlns:mulexml="http://www.mulesoft.org/schema/mule/xml" xmlns:data-mapper="http://www.mulesoft.org/schema/mule/ee/data-mapper" xmlns:xm="http://www.mulesoft.org/schema/mule/xml" xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns:file="http://www.mulesoft.org/schema/mule/file" xmlns:jms="http://www.mulesoft.org/schema/mule/jms" 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.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.mulesoft.org/schema/mule/ee/jdbc http://www.mulesoft.org/schema/mule/ee/jdbc/current/mule-jdbc-ee.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.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/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/jms http://www.mulesoft.org/schema/mule/jms/current/mule-jms.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/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/ee/data-mapper http://www.mulesoft.org/schema/mule/ee/data-mapper/current/mule-data-mapper.xsd
http://www.mulesoft.org/schema/mule/quartz http://www.mulesoft.org/schema/mule/quartz/current/mule-quartz.xsd
http://www.mulesoft.org/schema/mule/ee/tracking http://www.mulesoft.org/schema/mule/ee/tracking/current/mule-tracking-ee.xsd">
<jms:activemq-connector name="Active_MQ" brokerURL="tcp://localhost:61616" validateConnections="true" doc:name="Active MQ"></jms:activemq-connector>
<xm:jaxb-context name="myJaxb" doc:name="myJaxb" packageNames="com.test.jaxb"></xm:jaxb-context>
<spring:beans>
<spring:bean id="springDataSource" name="Bean" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<spring:property name="url" value="jdbc:mysql://localhost:3306/muledb"></spring:property>
<spring:property name="maxActive" value="30"></spring:property>
<spring:property name="removeAbandoned" value="true"></spring:property>
<spring:property name="driverClassName" value="com.mysql.jdbc.Driver"></spring:property>
<spring:property name="initialSize" value="20"></spring:property>
<spring:property name="username" value="root"></spring:property>
</spring:bean>
</spring:beans>
<quartz:connector name="quartzConnector" doc:name="Quartz">
<quartz:factory-property key="org.quartz.scheduler.instanceName" value="MuleScheduler1"></quartz:factory-property>
<quartz:factory-property key="org.quartz.threadPool.class" value="org.quartz.simpl.SimpleThreadPool"></quartz:factory-property>
<quartz:factory-property key="org.quartz.threadPool.threadCount" value="3"></quartz:factory-property>
<quartz:factory-property key="org.quartz.scheduler.rmi.proxy" value="false"></quartz:factory-property>
<quartz:factory-property key="org.quartz.scheduler.rmi.export" value="false"></quartz:factory-property>
<quartz:factory-property key="org.quartz.jobStore.class" value="org.quartz.simpl.RAMJobStore"></quartz:factory-property>
</quartz:connector>
<jdbc-ee:mysql-data-source name="MySQL_Data_Source" user="root" password="" url="jdbc:mysql://localhost:3306/muledb" transactionIsolation="UNSPECIFIED" doc:name="MySQL Data Source"></jdbc-ee:mysql-data-source>
<jdbc-ee:connector name="Database" dataSource-ref="MySQL_Data_Source" validateConnections="true" transactionPerMessage="false" queryTimeout="-1" pollingFrequency="0" doc:name="Database"></jdbc-ee:connector>
<!-- <flow name="JMSMessageFlow1" doc:name="JMSMessageFlow1" >
<jdbc-ee:inbound-endpoint queryKey="FirstUpdate" queryTimeout="-1" connector-ref="Database" doc:name="Database" pollingFrequency="0">
<jdbc-ee:query key="FirstUpdate" value="SELECT * FROM gcp_txn_log WHERE PROCESSED= 'Y'"></jdbc-ee:query>
<jdbc-ee:query key="FirstUpdate.ack" value="update gcp_txn_log set PROCESSED='N' where service_id = #[map-payload:service_id]"></jdbc-ee:query>
</jdbc-ee:inbound-endpoint>
<logger level="INFO" doc:name="Logger"/>
</flow> -->
<!-- <flow name="JMSMessageFlow2" doc:name="JMSMessageFlow2">
<jdbc-ee:inbound-endpoint queryKey="SelectAll" queryTimeout="-1" connector-ref="Database" doc:name="Database" pollingFrequency="0">
<jdbc-ee:transaction action="ALWAYS_BEGIN"></jdbc-ee:transaction>
<jdbc-ee:query key="SelectAll" value="SELECT * FROM gcp_txn_log WHERE PROCESSED= 'N'"></jdbc-ee:query>
<jdbc-ee:query key="SelectAll.ack" value="update gcp_txn_log set PROCESSED='Y' where service_id = #[map-payload:service_id] "></jdbc-ee:query>
</jdbc-ee:inbound-endpoint>
<xm:object-to-xml-transformer doc:name="Object to XML"></xm:object-to-xml-transformer>
<file:outbound-endpoint path="C:\Users\FASYL\Downloads" outputPattern="test#[function:datestamp:dd-MM-yy]_#[function:systime].xml" responseTimeout="10000" doc:name="File"></file:outbound-endpoint>
<jdbc-ee:outbound-endpoint queryKey="FirstUpdate" queryTimeout="-1" connector-ref="Database" doc:name="Database">
<jdbc-ee:query key="FirstUpdate" value="update gcp_txn_log set PROCESSED = 'N' WHERE PROCESSED = 'Y'"></jdbc-ee:query>
</jdbc-ee:outbound-endpoint>
</flow> -->
<flow name="JMSMessageFlow3" doc:name="JMSMessageFlow3">
<quartz:inbound-endpoint jobName="job2" repeatInterval="1" repeatCount="0" responseTimeout="10000" doc:name="Quartz" connector-ref="quartzConnector">
<quartz:event-generator-job>
<quartz:payload>Setting Session Variable</quartz:payload>
</quartz:event-generator-job>
</quartz:inbound-endpoint>
<component class="com.test.SchedulerComponent" doc:name="Java"></component>
<component doc:name="Java">
<singleton-object class="com.test.ServiceDAO">
<property key="dataSource" value-ref="springDataSource" value="null"/>
</singleton-object>
</component>
<message-properties-transformer scope="session" doc:name="Message Properties">
<add-message-property key="serviceDAO" value="#[message.payload]"/>
</message-properties-transformer>
<logger level="INFO" doc:name="Logger" message="#[sessionVars['serviceDAO']['1001']]"/>
</flow>
<!-- <flow name="JMSMessageFlow1" doc:name="JMSMessageFlow1">
</flow> -->
<flow name="JMSMessageFlow4" doc:name="JMSMessageFlow4">
<jms:inbound-endpoint queue="StudioIns" connector-ref="Active_MQ" doc:name="JMS"/>
<xm:jaxb-xml-to-object-transformer jaxbContext-ref="myJaxb" returnClass="com.test.jaxb.MsgContent"></xm:jaxb-xml-to-object-transformer>
<choice doc:name="Choice">
<when expression="payload.getMsgBody().getValue() == 'fundstransfer'" >
<pooled-component doc:name="Java">
<prototype-object class="com.test.PersonComponent">
<property key="dataSource" value-ref="springDataSource" value="null"/>
</prototype-object>
</pooled-component>
</when>
<when expression="#[sessionVars['serviceDAO']['1001'] == 1] ">
<pooled-component doc:name="Java">
<prototype-object class="com.test.SecondPersonComponent">
<property key="dataSource" value-ref="springDataSource" value="null"/>
</prototype-object>
</pooled-component>
</when>
</choice>
<logger message="#[sessionVars['serviceDAO']]" level="INFO" doc:name="Logger"/>
<file:outbound-endpoint path="D:\Documents\MuleStudio\workspace\jms_amq\bin\com\test" outputPattern="new.txt" responseTimeout="10000" doc:name="File"/>
</flow>
</mule>
The error indicates your payload is a HashMap: "Message payload is of type: HashMap". So the expression: message.payload.getServiceCodes() won't work as a HashMap doesn't have a method named 'getServiceCodes()'. If you want access elements of that HashMap you can use MEL(Mule Expression Language - http://www.mulesoft.org/documentation/display/current/Mule+Expression+Language+MEL) in a few ways.
Either via standard java method invocation such as:
payload.get('mykey')
or you can use MEL short hand such as:
payload['mykey'] or payload.mykey
Ont he other point about session variables you can store it in a session variable via the "set-session-variable" message processor and access the elements in a similar way. You can refer to it using "sessionVars" instead of "payload" and this time it will be a map of maps so:
sessionVars.mymap.mykey or sessionVars['mymap']['mykey'] etc.

Mule - test an http get request with choice component

I have the following flow :
<flow name="SOAPWebService" doc:name="SOAPWebService">
<http:inbound-endpoint address="http://localhost:8088/esb/" exchange-pattern="request-response" doc:name="HTTP">
</http:inbound-endpoint>
<choice doc:name="Choice">
<when expression="#[payload.contains('c22')]">
<set-variable variableName="paramCtr" value="#[message.inboundProperties['ctr']]" doc:name="conteneur"/>
<set-variable variableName="paramC" value="#[message.inboundProperties['c']]" doc:name="critere"/>
<component class="com.example.components.SampleComponent" doc:name="Java"/>
<mulexml:xslt-transformer maxIdleTransformers="2" maxActiveTransformers="5" xsl-file="C:\MuleStudio\SandBox\resources\PrepareRequestXMLPort.xsl" doc:name="XSLT">
<mulexml:context-property key="paramCtr" value="#[flowVars['paramCtr']]"/>
<mulexml:context-property key="paramC" value="#[flowVars['paramC']]"/>
</mulexml:xslt-transformer>
<cxf:proxy-client payload="body" enableMuleSoapHeaders="true" doc:name="SOAP"/>
<http:outbound-endpoint exchange-pattern="request-response" address="http://localhost:8080/ClientsDB/port" doc:name="PortWS"/>
</when>
<otherwise>
<set-variable variableName="paramCtr" value="#[message.inboundProperties['ctr']]" doc:name="conteneur"/>
<set-variable variableName="paramC" value="#[message.inboundProperties['c']]" doc:name="critere"/>
<component class="com.example.components.SampleComponent" doc:name="Java"/>
<mulexml:xslt-transformer maxIdleTransformers="2" maxActiveTransformers="5" xsl-file="C:\MuleStudio\SandBox\resources\PrepareRequestXMLDouane.xsl" doc:name="XSLT">
<mulexml:context-property key="paramCtr" value="#[flowVars['paramCtr']]"/>
<mulexml:context-property key="paramC" value="#[flowVars['paramC']]"/>
</mulexml:xslt-transformer>
<cxf:proxy-client payload="body" enableMuleSoapHeaders="true" doc:name="SOAP"/>
<http:outbound-endpoint exchange-pattern="request-response" address="http://localhost:8080/ClientsDB/douane" doc:name="DouaneWS"/>
</otherwise>
</choice>
<byte-array-to-string-transformer doc:name="Byte Array to String" />
<file:outbound-endpoint path="C:\MuleStudio\SandBox\output" outputPattern="#[function:datestamp:dd-MM-yy]_#[function:systime].xml " responseTimeout="10000" doc:name="Outgoing File"/>
I want to test if an http request like http://localhost:8088/esb/?type=xxxx&id=1234 if it contains the String xxxx in a way to route the request to the desired web service proxy.
I've tried withe the expression expression="#[string.contains['xxxxx']]" but it does not seem to work.
any idea?
thank you.
Two things: You will need to replace "string" with the property you want to execute on. Either a message property or payload etc. i.e #[payload.contains...].
"contains" is a Java method on java.lang.String so you need to use standard Java method invocation with () instead of [].
Working example:
<choice doc:name="Choice">
<when expression="#[payload.contains('xxxx')]">
<logger level="ERROR" message="YES" />
</when>
<otherwise>
<logger level="ERROR" message="NO" />
</otherwise>
</choice>
Or directly work off inbound properties for your query params:
After your http inbound use set-variable to store your query params into flow variables.
And then use the flow variales in your expression.
<set-variable value="#[message.inboundProperties['id']]" variableName="paramId"></set-variable>
<set-variable value="#[message.inboundProperties['type']]" variableName="paramType"></set-variable>
or you can directly use inbound property for comparision.
<when expression="#[message.inboundProperties['type']== 'XXXX']">

Mule - choice component issue

When I run my flow, I get the following error `
<org.apache.cxf.staxutils.DepthXMLStreamReader>
<reader class="org.mule.module.cxf.support.StreamClosingInterceptor$1">
<reader class="com.ctc.wstx.sr.ValidatingStreamReader">
<mXml11>false</mXml11>
<mInputBuffer>xmlns:ns2="http://wsdouane/"><return><douanePK><idConteneurId>ctr1</idConteneurId><idCritereId>C11</idCritereId></douanePK><valeurId>oui</valeurId></return></ns2:findResponse></S:Body></S:Envelope>.................
we can see the correct soap response starting from the <mInputBuffer>, is there a way to get only the soap response??
here is my flow
<flow name="SOAPWebService" doc:name="SOAPWebService">
<http:inbound-endpoint exchange-pattern="request-response" address="http://localhost:8088/esb" doc:name="HTTP"/>
<object-to-string-transformer doc:name="Object to String"/>
<choice doc:name="Choice">
<when expression="#[payload.contains('C22')]">
<set-variable variableName="paramCtr" value="#[message.inboundProperties['ctr']]" doc:name="conteneur"/>
<set-variable variableName="paramC" value="#[message.inboundProperties['c']]" doc:name="critere"/>
<component class="com.example.components.SampleComponent" doc:name="Java"/>
<mulexml:xslt-transformer maxIdleTransformers="2" maxActiveTransformers="5" xsl-file="C:\MuleStudio\SandBox\resources\PrepareRequestXMLPort.xsl" doc:name="XSLT">
<mulexml:context-property key="paramCtr" value="#[flowVars['paramCtr']]" />
<mulexml:context-property key="paramC" value="#[flowVars['paramC']]" />
</mulexml:xslt-transformer>
<cxf:proxy-client payload="body" enableMuleSoapHeaders="true" doc:name="SOAP"/>
<http:outbound-endpoint exchange-pattern="request-response" address="http://localhost:8080/ClientsDB/port" doc:name="PortWS"/>
<byte-array-to-string-transformer doc:name="Byte Array to String" />
</when>
<otherwise>
<set-variable variableName="paramCtr" value="#[message.inboundProperties['ctr']]" doc:name="conteneur"/>
<set-variable variableName="paramC" value="#[message.inboundProperties['c']]" doc:name="critere"/>
<component class="com.example.components.SampleComponent" doc:name="Java"/>
<mulexml:xslt-transformer maxIdleTransformers="2" maxActiveTransformers="5" xsl-file="C:\MuleStudio\SandBox\resources\PrepareRequestXMLDouane.xsl" doc:name="XSLT">
<mulexml:context-property key="paramCtr" value="#[flowVars['paramCtr']]" />
<mulexml:context-property key="paramC" value="#[flowVars['paramC']]" />
</mulexml:xslt-transformer>
<cxf:proxy-client payload="body" enableMuleSoapHeaders="true" doc:name="SOAP"/>
<http:outbound-endpoint exchange-pattern="request-response" address="http://localhost:8080/ClientsDB/douane" doc:name="DouaneWS"/>
<byte-array-to-string-transformer doc:name="Byte Array to String"/>
</otherwise>
</choice>
<xm:object-to-xml-transformer doc:name="Object to XML"/>
<file:outbound-endpoint path="C:\MuleStudio\SandBox\output" outputPattern="#[function:datestamp:dd-MM-yy]_#[function:systime].xml " responseTimeout="10000" doc:name="Outgoing File"/>
</flow>
thank you.
This expression #[payload.contains('c22')] can't work because the payload is an InputStream. Aren't you seeing stack traces in Mule's logs?
In any case, try adding <object-to-string-transformer /> before the choice and see if it fixes the issue.
EDIT:
The problem is that you're using XStream (in xm:object-to-xml-transformer) to serialize the CXF response object (org.apache.cxf.staxutils.DepthXMLStreamReader) into XML. The CXF response should not be messed with and should be handled by the cxf:proxy-client in the response phase of the flow. The xm:object-to-xml-transformer and file:outbound-endpoint after the choice router are probably disturbing this mechanism. Try to wrap them in a response element above the choice router to they execute after it in the response phase.
Note that I have already given you this advice in your other question https://stackoverflow.com/a/16615537/387927 but you did not react to it.
Also I don't think byte-array-to-string-transformer does anything: the message payload after the http:outbound-endpoints should be org.apache.cxf.staxutils.DepthXMLStreamReader, preventing this transformer to fire.

Resources