Mule ESB: JMS selector expression not working - mule

I have a Mule integration that implements the pub-sub model. The publisher publishes the message to a topic and the subscriber is configured to receive the messages from this topic. I want to have this subscriber receive the messages only if a custom property named 'ENTITY_TYPE' has values either of the following: 'accounts', 'contacts' or 'cases'. Unfortunately this is not working (I mean the subscriber doesn't receive the message at all). Here is the code snippets:
Publisher:
AccountsFlow:
<set-property propertyName="ENTITY_TYPE" value="accounts" doc:name="Set Entity Type"/>
<jms:outbound-endpoint connector-ref="Active_MQ_Publisher" doc:name="Publish Accounts" topic="${activemq.sfdc.topicname}" tracking:enable-default-events="true"/>
ContactsFlow:
<set-property propertyName="ENTITY_TYPE" value="contacts" doc:name="Set Entity Type"/>
<jms:outbound-endpoint connector-ref="Active_MQ_Publisher" doc:name="Publish Contacts" topic="${activemq.sfdc.topicname}" tracking:enable-default-events="true"/>
CasesFlow:
<set-property propertyName="ENTITY_TYPE" value="cases" doc:name="Set Entity Type"/>
<jms:outbound-endpoint connector-ref="Active_MQ_Publisher" doc:name="Publish Cases" topic="${activemq.sfdc.topicname}" tracking:enable-default-events="true"/>
Subscriber:
<jms:inbound-endpoint connector-ref="Active_MQ_Subscriber" doc:name="JMS" tracking:enable-default-events="true" topic="${activemq.sfdc.topicname}">
<jms:selector expression="ENTITY_TYPE='accounts' OR ENTITY_TYPE='contacts' OR ENTITY_TYPE='cases'" />
</jms:inbound-endpoint>
<logger message="$$$: Entity Type = #[message.inboundProperties['ENTITY_TYPE']]" level="INFO" doc:name="Logger"/>
If I remove the 'jms:selector' element, then I do see the output in the logs:
2015-06-18 15:58:19,574 INFO o.m.a.p.LoggerMessageProcessor [[sfdcjob].AccountsContactsCasesSubscriberFlow.stage1.02] $$$: Entity Type = sfdc.locationheader
Here is the env details:
Mule Standalone: 3.6.2 (Enterprise Edition)
OS: Cent OS 7
Message Broker: Active MQ 5.11.1
JVM for both Mule & Active MQ: 1.7.0.75
I certainly need to set the filter and interested to receive only the messages whose message property is set to one of the values defined previously (accounts, contacts, cases). Any idea why the JMS selector not working?
Edit: I tried another way to set the entity type in the publisher as follows and that also didn't work.
<jms:outbound-endpoint connector-ref="Active_MQ_Publisher" doc:name="Publish Accounts" topic="${activemq.sfdc.topicname}" tracking:enable-default-events="true">
<message-properties-transformer doc:name="Message Properties" scope="outbound">
<add-message-property key="ENTITY_TYPE" value="accounts" />
</message-properties-transformer>
</jms:outbound-endpoint>

Related

How to acknowledge the activemq message in mule using client acknowledge?

Below is my mule configuration, i want to acknowledge using client acknoledge , how can i do it?
<mule>
<jms:activemq-connector name="Active_MQ" brokerURL="tcp://localhost:61616" validateConnections="true" doc:name="Active MQ" maxRedelivery="2" persistentDelivery="true"/>
<flow name="activemqFlow">
<file:inbound-endpoint path="D:\mule\input" responseTimeout="10000" doc:name="File"/>
<object-to-string-transformer doc:name="Object to String"/>
<set-property propertyName="fileName" value="#[message.inboundProperties.originalFilename]" doc:name="Property"/>
<jms:outbound-endpoint queue="logfilequeue" connector-ref="Active_MQ" doc:name="JMS">
<jms:transaction action="NONE"/>
</jms:outbound-endpoint>
</flow>
<flow name="JmsInboundFlow">
<jms:inbound-endpoint queue="logfilequeue" connector-ref="Active_MQ" doc:name="JMS">
<jms:client-ack-transaction action="ALWAYS_BEGIN"/>
</jms:inbound-endpoint>
<logger message="#[payload.toString()]" level="INFO" doc:name="Logger"/>
<file:outbound-endpoint path="D:\mule\output" responseTimeout="10000" doc:name="File" outputPattern="#[message.inboundProperties.fileName]"/>
</flow>
</mule>
Note: Be REALLY sure you want to use CLIENT_ACKNOWLEDGE it doesn't work like most people think. It ack's the current message AND all previous within the session. If you have parallel/threaded consumers this setting will inadvertently ack messages that aren't ready to be ack'd yet. ActiveMQ has a INDIVIDUAL_ACKNOWLEDGE which ack's just the single message.
JMS Spec 2.0 has feat requests to make this add'l ack mode a standard.
Try adding acknowledgementMode="CLIENT_ACKNOWLEDGE" in your JMS connector.
You can refer this question for more details
Mule jms with CLIENT_ACKNOWLEDGE mode? Message automatically consumed even though I didn't acknoeledge it

Mule JMS Topic and ActiveMQ Configuration

I am using Mule ESB to design a process whereby one can post a message to a topic. Subscribers will listen to the topic and receive messages. Each subscriber will act on the messages differently. The goal here is to have the ability to post a test message to the topic from HTTP for testing subscribers.
Here is how I have the JMS connection configured:
<!-- JMS Topic connector -->
<jms:activemq-connector name="jmsTopicConnection" specification="1.1" brokerURL="tcp://localhost:61616" validateConnections="true" doc:name="Active MQ2" durable="true" numberOfConcurrentTransactedReceivers="2"/>
This is the flow:
<flow name="auditJMSServiceFlow">
<http:listener config-ref="HTTP" path="/Audit/Activity" responseStreamingMode="ALWAYS" doc:name="HTTP"/>
<set-variable variableName="#['id']" value="#[message.inboundProperties['id']]" doc:name="set dynamic id"/>
<set-payload value="===TOPIC===" doc:name="Set Payload" />
<request-reply storePrefix="mainFlow">
<jms:inbound-endpoint topic="Audit.Activity" connector-ref="jmsTopicConnection" doc:name="JMS Topic Audit.Activity" exchange-pattern="request-response" durableName="audit_activity">
<jms:transaction action="ALWAYS_BEGIN" />
<!-- Not required to explicitly have this element. Mule will put this in implicitly. -->
<!-- <jms:jmsmessage-to-object-transformer displayName="JmsMsg to Object"/> -->
</jms:inbound-endpoint>
</request-reply>
<json:object-to-json-transformer doc:name="transform JMS message to JSON"/>
<json:validate-schema schemaLocation="resource://AuditMsgSchema.json" doc:name="Validate Json Schema"/>
<component class="com.baml.panther.audit.service.impl.AuditServiceImpl" doc:name="Java"/>
<default-exception-strategy>
<commit-transaction exception-pattern="com.foo.ExpectedExceptionType"/>
<jms:outbound-endpoint queue="dead.letter" connector-ref="jmsConnection">
<jms:transaction action="JOIN_IF_POSSIBLE" />
</jms:outbound-endpoint>
</default-exception-strategy>
<logger message="=== #[message.payload] received #[org.mule.util.DateUtiles.getTimeStamp('dd-MM-yyyy_HH-mm-ss.SSS')]" level="INFO" doc:name="Logger"/>
When I am running through the test I get the following error:
Any suggestions would be greatly appreciated.
Russ
For the error: Your request-reply scope is missing an outbound endpoint. You only have the inbound-endpoint (jms:inbound-endpoint). You need to provide the outbound-endpoint as well.
<request-reply storePrefix="mainFlow">
<jms:inbound-endpoint topic="Audit.Activity" connector-ref="jmsTopicConnection" doc:name="JMS Topic Audit.Activity" exchange-pattern="request-response" durableName="audit_activity">
<jms:transaction action="ALWAYS_BEGIN" />
<!-- Not required to explicitly have this element. Mule will put this in implicitly. -->
<!-- <jms:jmsmessage-to-object-transformer displayName="JmsMsg to Object"/> -->
</jms:inbound-endpoint>
</request-reply>
Not sure what your aim there but if you put just a jms:outbound-enpoint (instead of the whole request-reply block), you can send a message to the JMS topic.
The problem is that you cannot put a message source as the first message processor in a request-reply. The request reply allows you a kind of synchronous call for async protocols like JMS.
If you want to send a message to the message broker at the point where you put the request-reply just put a JMS outbound-endpoint.
If what you want to do is consume a message from the JMS topic you have to put a JMS inbound endpoint as the first message processor in a flow.

How to Intercept incoming call in Mule

Hi I am working with Mule Any Point platform i am using composite source which is listening from HTTP and JMS both. I want to identify the incoming call coming from HTTP or JMS and i want to print using the logger. How to do that ?
Try the following way of using logger inside your endpoints.
<composite-source doc:name="Composite Source">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" doc:name="HTTP">
<logger message="Request coming from HTTP endpoint."></logger>
<set-variable value="HTTP" variableName="myVar"></set-variable>
</http:inbound-endpoint>
<jms:inbound-endpoint doc:name="JMS" queue="in">
<logger message="Request coming from JMS endpoint."></logger>
<set-variable value="JMS" variableName="myVar"></set-variable>
</jms:inbound-endpoint>
</composite-source>
In the flow when you have to chekc a condition, you can use the flow variable "myVar" to check whether the message came from HTTP or JMS endpoint.
Hope this helps.

Using Mule instances in a master/slave or failover relationship

I have two Mule instances subscribed to the same topic on a queue but I only want each message consumed once.
I can achieve this by funneling messages to unique queue and processing from there, but to reduce the operational complexity I want to set up the message consumer flow running on each Mule instance to defer to one of the instances.
This would be akin to an ActiveMQ failover setup (where only one instance is running at a time and idle instances only awaken when the running instance fails to respond) or a master/slave arrangement where I would grant one of the instances command over the others. Or like a VM transport that is inter-instance instead of intra-instance.
This would need to be done without any Mule Enterprise Edition components (relying only upon Mule Community Edition components) using Mule versions 3.4. or 3.5.
I was unable to find a convenient built-in way to do this. Instead I assume that each mule instance will run on a separate box and use the server.host value to determine which instance does the processing:
<mule xmlns:redis="http://www.mulesoft.org/schema/mule/redis"
xmlns="http://www.mulesoft.org/schema/mule/core"
version="CE-3.5.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.mulesoft.org/schema/mule/redis http://www.mulesoft.org/schema/mule/redis/3.4/mule-redis.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd">
<!-- define redis instance -->
<redis:config name="redis-instance" />
<flow name="topicConsumer">
<!-- listen to redis channel (topic) -->
<redis:subscribe config-ref="redis-instance">
<redis:channels>
<redis:channel>topic.channel</redis:channel>
</redis:channels>
</redis:subscribe>
<!-- save original payload (message from Redis) -->
<set-session-variable variableName="redisPayload" value="#[payload]" />
<!-- select processor -->
<flow-ref name="topicProcessorSelector"/>
<choice>
<when expression="#[sessionVars['subscriberProcessor'] == server.host]">
<logger level="INFO" message="processing on #[server.host]"/>
</when>
<otherwise>
<logger level="INFO" message="take no action"/>
</otherwise>
</choice>
</flow>
<flow name="topicProcessorSelector" processingStrategy="synchronous">
<!-- get key -->
<redis:get config-ref="redis-instance"
key="topic_processor"/>
<!-- if no key, then add this instance as the processor -->
<choice>
<when expression="#[payload instanceof org.mule.transport.NullPayload]">
<!-- set key -->
<redis:set config-ref="redis-instance"
key="topic_processor"
expire="10"
value="#[server.host]">
</redis:set>
<set-session-variable variableName="subscriberProcessor" value="#[server.host]" />
</when>
<otherwise>
<!-- use existing key -->
<byte-array-to-string-transformer/>
<set-session-variable variableName="subscriberProcessor" value="#[payload]" />
</otherwise>
</choice>
</flow>
</mule>

Mule - mixing exchange patterns

I am trying to understand what is going one when i mix exchange patterns.
If i call a vm request-response inbound endpoint with a ones-way outbound endpoint, there is no error but it appears as though the flow is never run for example:
<flow name="main" doc:name="main" processingStrategy="asynchronous">
<poll frequency="60000">
<set-payload value="main"></set-payload>
</poll>
<set-variable value="xxx" variableName="var1"></set-variable>
<logger level="ERROR" message="MAIN1 #[flowVars.var1]" />
<vm:outbound-endpoint address="vm://vm" />
<logger level="ERROR" message="MAIN2 #[flowVars.var1]" />
</flow>
<flow name="p1">
<vm:inbound-endpoint address="vm://vm" exchange-pattern="request-response" />
<logger level="ERROR" message="PRIVATE #[flowVars.var1]" />
</flow>
</mule>
This configuration logs the following, but never prints 'PRIVATE xxx'.
ERROR 2014-03-26 13:22:35,794 [[test].main.stage1.01] org.mule.api.processor.LoggerMessageProcessor: MAIN1 xxx
ERROR 2014-03-26 13:22:35,812 [[test].main.stage1.01] org.mule.api.processor.LoggerMessageProcessor: MAIN2 xxx
INFO 2014-03-26 13:22:35,816 [[test].connector.VM.mule.default.dispatcher.01] org.mule.lifecycle.AbstractLifecycleManager: Initialising: 'connector.VM.mule.default.dispatcher.784920740'. Object is: VMMessageDispatcher
INFO 2014-03-26 13:22:35,817 [[test].connector.VM.mule.default.dispatcher.01] org.mule.lifecycle.AbstractLifecycleManager: Starting: 'connector.VM.mule.default.dispatcher.784920740'. Object is: VMMessageDispatcher
And if I mix them the other way around MAIN2 xxx never prints. Can someone explain what actually is going on here?
Mule docs state the following:
request-response:
When using request-response endpoints, messages are
delivered directly from an outbound vm endpoint to the inbound vm
endpoint that is listening on the same path. This delivery is blocking
and occurs in the same thread. If there is no inbound request-response
vm endpoint in the same Mule application listening on this path, then
dispatching of the message from the outbound endpoint will fail.
one-way:
When using one-way endpoints, messages are delivered to the
corresponding inbound endpoint via a queue. This delivery is
non-blocking. If there is no inbound one-way endpoint in the same Mule
application listening on this path, then, although dispatching of the
message will succeed, the message will remain in the queue. By
default, this queue is in memory, but it is also possible to configure
a persistent queue that will use the file system as its persistence
mechanism.
http://www.mulesoft.org/documentation/display/current/VM+Transport+Reference
I would guess the case with request-response outbound just remains waiting for a response, as the message gets dispatched and received contrary to the docs.
I don't mean to be rude, but It doesn't make sense to mix echange patterns this way. I believe one should never do something like this. In fact it's better to configure your exchange pattern on the vm endpoint globally, so that you have have consistent endpoints and you can't make mistakes.
<vm:endpoint name="vm-endp" path="vm-endp" exchange-pattern="request-response" />
<flow name="main" doc:name="main" processingStrategy="asynchronous">
<http:inbound-endpoint exchange-pattern="one-way" name="http-endpoint" host="localhost" port="2003" path="mule" doc:name="HTTP"/>
<set-variable variableName="var1" value="xxx" doc:name="XXX" />
<logger level="INFO" message="MAIN1 #[flowVars.var1]" />
<set-payload value="#[flowVars.var1]" />
<vm:outbound-endpoint ref="vm-endp" />
<logger level="INFO" message="MAIN2 #[flowVars.var1]" />
<logger level="INFO" message="PAYLOAD #[message.payloadAs(java.lang.String)]" />
</flow>
<!-- flowVars are FLOW VARIABLES, hence they're not accessible from multiple flows -->
<flow name="flow">
<vm:inbound-endpoint ref="vm-endp" />
<logger level="INFO" message="PRIVATE #[flowVars.var1]" />
<append-string-transformer message=" added to the payload" />
</flow>
It should output:
INFO [[VMtest].main.stage1.01] org.mule.api.processor.LoggerMessageProcessor: MAIN1 xxx
INFO [[VMtest].main.stage1.01] org.mule.lifecycle.AbstractLifecycleManager: Initialising: 'connector.VM.mule.default.dispatcher.1221995064'. Object is: VMMessageDispatcher
INFO [[VMtest].main.stage1.01] org.mule.lifecycle.AbstractLifecycleManager: Starting: 'connector.VM.mule.default.dispatcher.1221995064'. Object is: VMMessageDispatcher
INFO [[VMtest].main.stage1.01] org.mule.api.processor.LoggerMessageProcessor: PRIVATE null
INFO [[VMtest].main.stage1.01] org.mule.api.processor.LoggerMessageProcessor: MAIN2 xxx
INFO [[VMtest].main.stage1.01] org.mule.api.processor.LoggerMessageProcessor: PAYLOAD xxx added to the payload