JMS Message Selector in Mule using date - mule

In Mule 3.3.1, during async processing, when any of my external services are down, I would like to place the message on a queue (retryQueue) with a particular "next retry" timestamp. The flow that processes messages from this retryQueue selects messages based on "next retry" time as in if "next retry" time is past current time, select the message for processing. Similar to what has been mentioned in following link.
Retry JMS queue implementation to deliver failed messages after certain interval of time
Could you please provide sample code to achieve this?
I tried:
<on-redelivery-attempts-exceeded>
<message-properties-transformer scope="outbound">
<add-message-property key="putOnQueueTime" value="#[function:datestamp:yyyy-MM-dd hh:mm:ssZ]" />
</message-properties-transformer>
<jms:outbound-endpoint ref="retryQueue"/>
</on-redelivery-attempts-exceeded>
and on the receiving flow
<jms:inbound-endpoint ref="retryQueue">
<!-- I have no idea how to do the selector....
I tried....<jms:selector expression="#[header:INBOUND:putOnQueueTime > ((function:now) - 30)]"/>, but obviously it doesn't work. Gives me an invalid message selector. -->
</jms:inbound-endpoint>.
Another note: If I set the outbound property using
<add-message-property key="putOnQueueTime" value="#[function:now]"/>,
it doesn't get carried over as part of header. That's why I changed it to:
<add-message-property key="putOnQueueTime" value="#[function:datestamp:yyyy-MM-dd hh:mm:ssZ]" />

The expression in:
<jms:selector expression="#[header:INBOUND:putOnQueueTime > ((function:now) - 30)]"/>
should evaluate to a valid JMS selector, which is not the case here. Try with:
<jms:selector expression="putOnQueueTime > #[XXX]"/>
replacing XXX with an expression that creates the time you want.

We were trying to achieve this in one of the projects I'm working on, and tried what was being suggested in the other answer here, and it did not work, with various variantions. The problem is that the jms:selector doesn't support MEL, since it's relies on ActiveMQ classes.
We registered a support-ticket to Mulesoft, and their reply was that this is not supported.
What we ended up doing was this:
Create a simple Component, which does a Thread.sleep(numberOfMillis), where the number of millis is defined in a property.
In the flow that was supposed to delay processing, we added this component as the first step after reading the message from the inbound endpoint.
Not the best solution ever made, but it works..

Related

Mule:Retrieving object store in an MEL in Mule 3.5

Having a requirement to test a object store whether it contains a key or not in a choice router
<objectstore:config name="storeDownload" doc:name="ObjectStore" persistent="false" partition="test"/>
<choice>
<when expression="#[app.registry.storeDownload.contains('#[flowVars.startKey]').equals('false')]">
Getting an error
1. Expression Evaluator "registry" with expression "ON" returned null but a value was required. (org.mule.api.expression.ExpressionRuntimeException)
org.mule.expression.RegistryExpressionEvaluator:101 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/expression/ExpressionRuntimeException.html)
2. Failed to invoke store. Message payload is of type: byte[] (org.mule.api.MessagingException)
The main issue is that you are embedding MEL into MEL which can't work. Also the boolean-as-string comparison is dodgy.
Replace this:
#[app.registry.storeDownload.contains('#[flowVars.startKey]').equals('false')]
with that:
#[!(app.registry.storeDownload.contains(flowVars.startKey))]
My use case was a bit different to Nazar's I needed to monitor a long running process which can take up to four hours.
In the first flow I generate a key value with a time stamp in it as the payload and then use it to set the ProcessState to the static value 'Started' in an ObjectStore as shown below. After which I fire a Quartz Outbound Endpoint with a four hour delay.
<objectstore:store config-ref="MonitoredProcess" value-ref="Started" key="#[payload]" doc:name="ObjectStore"/>
<quartz:outbound-endpoint jobName="ProcessMonitor" responseTimeout="10000" doc:name="Quartz"
repeatInterval="0" repeatCount="0" startDelay="${process.monitor.event.start.delay}">
<quartz:scheduled-dispatch-job>
<quartz:job-endpoint address="vm://processMonitorQueue"/>
</quartz:scheduled-dispatch-job>
</quartz:outbound-endpoint>
And I got the same exception.
After scratching my head and lots of searches the name of the variable 'value-ref' in combination with David's answer above finally revealed my problem namely the MEL is always invoked for this ref field.
As soon as I changed the field to an expression #['Started'] that MEL could evaluate my problem went away.
<objectstore:store config-ref="MonitoredProcess" value-ref="#['Started']" key="#[payload]" doc:name="ObjectStore"/>
For completeness I've included the code that retrieves the ProcessState from the ObjectStore. Note the defaultValue-ref also needs to use MEL
<vm:inbound-endpoint exchange-pattern="one-way" path="processMonitorQueue" doc:name="VM" />
<objectstore:retrieve config-ref="MonitoredProcess" defaultValue-ref="#['DoesNotExist']" key="#[payload]" targetProperty="processState" doc:name="ObjectStore"/>

Apache Camel get empty response from jetty

I face a complex case.
What I'm doing is as following steps:
1) <from uri="jetty:http://0.0.0.0:30100/jetty/test"/>
2) <to uri="hazelcast-client:master-test-series" />
3) <to uri="bean:modelSeriesWrapperTest" />
4)
<split parallelProcessing="true" streaming="true">
<simple>${body}</simple> <to uri="direct:dw.model.test"/>
</split>
5) From another route
<from uri="direct:dw.model.test"/>
<aggregate strategyRef="myAggregatorStrategy"
completionTimeout="1000">
<correlationExpression>
<constant>true</constant>
</correlationExpression>
<marshal ref="modelSeriesVariantColourGson" />
<camel:to uri="file:src/data/catask/output?fileName=output.xml"/>
</aggregate>
The problem is that the jetty response is empty. I use TCP trace to track the request and response, the Content-Length is 0. But the output.xml file has correct JSON format content.
Even I cross the <camel:to uri="file:src/data/catask/output?fileName=output.xml"/>. The jetty response is still empty.
I try the InOut pattern, it doesn't work as well.
It seems jetty return directly, not waiting split done. I try to set In and Out body, it doesn't work either. I Google every case that I can image. There is no helpful case.
Could you please help me? Thank you very much.
If you want the jetty response to include whatever information from your aggregator, then you must use the splitter only approach as documented at:
http://camel.apache.org/composed-message-processor.html
The splitter has built-in aggregation, and that ensures when the splitter is done, it aggregates also, and then you can use that as the jetty response.
When you use <aggregate> then it becomes a separate exchange. To understand this more then read more about the aggregate eip, and other SO, and in various Camel books etc.

Mule ESB: File outputpattern doesn't translate the pattern

I'm using Mule ESB CE 3.4. I have a requirement where I'm reading the configuration information from database and using it as the file name for the file outbound endpoint. Here is an example code (the code may not work as I have only given an outline)
<file:connector name="File-Data" autoDelete="false" streaming="true" validateConnections="true" doc:name="File" />
.....
<!-- Gets the configuration from database using a transformer. The transformer populates the configuration entries in a POJO and puts that in a session. -->
<custom-transformer class="com.test.DbGetConfigsTransformer" doc:name="Get Integration Configs"/>
....<!-- some code to process data -->
<logger message="$$$: #[sessionVars['currentFeed'].getFilePattern()]" doc:name="Set JSON File Name" /> -->
<file:outbound-endpoint path="/temp" outputPattern="#[sessionVars['currentFeed'].getFilePattern()]" responseTimeout="10000" mimeType="text/plain" connector-ref="File-Data" doc:name="Save File"/>
The above code throws the following error:
1. The filename, directory name, or volume label syntax is incorrect (java.io.IOException)
java.io.WinNTFileSystem:-2 (null)
2. Unable to create a canonical file for /temp/Test_User_#[function:datestamp:YYYYMMddhhmmss.sss] (org.mule.api.MuleRuntimeException)
org.mule.util.FileUtils:354 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/MuleRuntimeException.html)
3. Failed to route event via endpoint: DefaultOutboundEndpoint{endpointUri=file:///temp, connector=FileConnector
In the database table, the field name is called FilePattern and it has the value 'Test_User_#[function:datestamp:YYYYMMddhhmmss.sss]. If I hardcode the value or move this value to the mule configuration file
file.name=Test_User_#[function:datestamp:YYYYMMddhhmmss.sss]
and use the configuration property syntax (for e.g. ${file.name} in the 'outputpattern'), it works. But if I read the same from db and use it, it is not working and throwing the error. The logger displays as (which is read from the db)
$$$: Test_#[function:datestamp:YYYYMMddhhmmss.sss]
Any help is much appreciated.
If your datestamp format does not vary, you should just store the environment prefix in your db and use something like:
outputPattern="#[sessionVars['prefix']+server.dateTime.format('YYYYMMddhhmmss.sss')]"
If you need to use your current database values, you can use basic Java string methods to find the correct substrings. For example:
#[sessionVars['currentFeed'].getFilePattern().substring(0,sessionVars['currentFeed'].getFilePattern().indexOf('function')-2)+server.dateTime.format('YYYYMMddhhmmss.sss')]
If you use different datestamp formats, you can find that part as well using similar String methods. However, I still suggest you come up with an implementation that only stores the environment prefix in the db.

Mule Message Enricher Target Expression

I have a flow that takes a pair of dates inbound and then uses a message enricher to get a list of employees that worked on a specific job between those two dates. The result is a simple list of maps returned from a JDBC database. I got that saved into a flow variable without any trouble. The next enrichment is causing me trouble. I setup a for each loop that uses the employees list from the flow variable. This works great and I then need to execute another JDBC query for each of these employees to get all the time tickets they turned in between the two dates passed to the flow. The query works but I am having trouble defining the target expression to hold the result. I would like to see the target be a map with the employee id as the key and the tickets for the period (list of maps) be the value. Is there any way to do this? Is there a better way to save these results? After I get all the tickets, I need to summarize them in various ways and generate a report showing the detail as well as the analysis.
I am currently developing this in mule studio for the community runtime version 3.4.
Is this like something that you are looking for?
<set-variable variableName="maplistmap" value="#[new java.util.HashMap()]"/>
<foreach>
<jdbc-ee:outbound-endpoint exchange-pattern="request-response" queryKey="selekt" queryTimeout="-1" connector-ref="Database">
<jdbc-ee:query key="selekt" value="select * from mytable where id = #[payload]"/>
</jdbc-ee:outbound-endpoint>
<scripting:component>
<scripting:script engine="Groovy"><![CDATA[
flowVars["maplistmap"].put(payload[0].id, payload)
]]></scripting:script>
</scripting:component>
</foreach>
<logger message="#[flowVars.maplistmap]" level="INFO"/>

Multiple triggers to Quartz endpoint in Mule

Is there a way to configure a Quartz inbound endpoint in Mule to have multiple triggers? Say I want an event every day at 9:00, plus one at 1:00 a.m. on the first day of the month.
Here is what you might work for you --
<flow name="MultipleIBEndpoints" doc:name="MultipleIBEndpoints">
<composite-source doc:name="Composite Source">
<quartz:inbound-endpoint jobName="QuartzDaily" doc:name="Quartz Daily"
cronExpression="0 0 9 1/1 * ? *">
<quartz:event-generator-job>
<quartz:payload>dummy</quartz:payload>
</quartz:event-generator-job>
</quartz:inbound-endpoint>
<quartz:inbound-endpoint jobName="QuartzMonthly" doc:name="Quartz Monthly"
cronExpression="0 0 1 1 1/1 ? *">
<quartz:event-generator-job>
<quartz:payload>dummy</quartz:payload>
</quartz:event-generator-job>
</quartz:inbound-endpoint>
</composite-source>
<logger level="INFO" doc:name="Logger" />
</flow>
The above flow uses composite source scope which allows you to embed into a single message source two or more inbound endpoints.
In the case of Composite, the embedded building blocks are actually message sources (i.e. inbound endpoints) that listen in parallel on different channels for incoming messages. Whenever any of these receivers accepts a message, the Composite scope passes it to the first message processor in the flow, thus triggering that flow.
You can do you requirement just by using one quartz endpoint with the required quartz endpoint
CRON Expression 0 0 1,21 1 * *
Please refer to the below link for more tweaks.
Mulesoft quartz reference
wikipedia reference
List of Cron Expression examples
In that case you need to configure two crontrigger and add them to the scheduler.
Please go through the below link where i have described the whole thing.
Configure multiple cron trigger
Hope this will help.