MULE expression-transformer not accepted - mule

I'm trying to learn Mule ESB but get problems with example projects. Why are these lines
underlined red and not represented in the Message flow?
<expression-transformer name="returnAttachments">
<return-argument evaluator="attachments-list" expression="*.txt,*.ozb,*.xml" optional="false"/>
</expression-transformer>
I've cut and pasted these lines from mulesoft.org as part of a sample project.

#genjosanzo is right, the MEL equivalent would be:
<expression-transformer
expression="#[($.value in message.inboundAttachments.entrySet() if $.key ~= '(.*\\.txt|.*\\.ozb|.*\\.xml)')]" />

Mule studio has problem rendering nested elements (bug reported here)
Instead you can use the compact version and replace it with the following:
<expression-transformer expression="#[attachments-list:*.txt,*.ozb,*.xml]" doc:name="Expression" />
On a side note ever since mule 3.3.0 the new mule expression languages and it is recommended to rely on it whenever possible.

Related

Mule : Use dynamic config-ref based on input values

I'm trying to connect to SQL Database with some configuration. But based on the input from the API we are supposed to hit different DB.
As of now, we have the code as
<choice doc:name="Check myFlag">
<when expression="#[flowVars.myFlag == 'true']">
<db:stored-procedure config-ref="Database_Configuration_1" doc:name="DB_config_1">
<db:dynamic-query><![CDATA[#[flowVars.callSPName]]]></db:dynamic-query>
</db:stored-procedure>
</when>
<otherwise>
<db:stored-procedure config-ref="Database_Configuration_2" doc:name="DB_config_2">
<db:dynamic-query><![CDATA[#[flowVars.callSPName]]]></db:dynamic-query>
</db:stored-procedure>
</otherwise>
</choice>
Instead of repeating <db:stored-procedure../> twice, is there a way where I can set a flow var with the DB config reference and use it?
Something like,
<db:stored-procedure config-ref="#[flowvars.db_config]" doc:name="DB_config_2">
<db:dynamic-query><![CDATA[#[flowVars.callSPName]]]></db:dynamic-query>
</db:stored-procedure>
In Mule 3, no. config-ref's are evaluated at application startup, not runtime.
In Mule 4 this is possible using Dynamic Configurations: https://docs.mulesoft.com/mule-sdk/1.1/static-dynamic-configs
Potential Mule 3 solutions documented here: https://help.mulesoft.com/s/article/How-to-configure-connector-with-dynamic-parameters
Put the DB call inside a sub-flow and call it from the rest of the flows with a <flow-ref>.

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

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.

XPATH in mule flow returns multiple values

I have a requirement where I run xPath evaluator against xml payload in mule flow. This xPath evaluator can return single or multiple values. I need to store these values in flow variable and use somewhere later in the flow. Can someone help me implementing this changes?
Appreciate your help on this.
Thanks
For extracting values from an XML document, use the XPath extractor.
<mulexml:xpath-extractor-transformer expression="/a:my/b:xpath/text()"/>
You can also use Mule Expression Language to create dynamic XPath expressions:
<expression-transformer mimeType="text/xml" evaluator="xpath" expression="//school/day[#date= #[function:datestamp:yyyy-MM-dd] ]/name
"/>
However this can get somewhat messy for complicated expressions, so I have created my own dynamic XPath transformer:
<dx:dxpath expression="/b:team[name = $teamName]/b:player[b:name = $playerName]/b:goals/text()">
<dx:variable key="playerName" value="#[header:invocation:playerName]"/>
<dx:variable key="teamName" value="#[header:invocation:teamName]"/>
<!-- unlimited number of variables -->
</dx:dxpath>
which is somewhat more easy on the eyes.
Then Wrap your flow with an ericher:
<enricher target="#[variable:myData]">
<processor-chain>
<!-- your flow here -->
</processor-chain>
</enricher>

Mule choice compare

In mule flow I need to compare the last two params from an input string message
2012-04-30,2012-05-30,1,5
And if param1(1) <= param2(5), I need perform jms:outbound-endpoint.
Is there a standard choice element to do it? Could you please provide example.
While using mule 3.2.x your best option is to use the groovy evaluator and use a choice router that look like the following
<when expression="#[groovy:payload.split(',')[2] <= payload.split(',')[3] ]">
<processor-chain>
<jms:outbound-endpoint queue="out" doc:name="JMS"/>
</processor-chain>
</when>
Otherwise if you are willing to upgrade to Mule 3.3.0 you can take advantage of the new Mule Expression Language that allows to do the same without the need of the groovy operator
you can also use splitter and split on the basis of ',' and then have the compare logic for the params
You need not use Groovy for this. You can directly apply the split() function on payload.
<when expression="#[payload.split(',')[2]<=payload.split(',')[3]]">
<processor-chain doc:name="Processor Chain">
<jms:outbound-endpoint queue="data" connector-ref="Active_MQ"doc:name="JMS"/>
</processor-chain>
</when>
Apart from expression filter you can also use choice flow control. Capture the 2 values to be compared in a flowvars and use below expression in when condition of choice flow control.
[flowVars.param1 <= flowVars.param1]
Giving below the link for more information.
https://docs.mulesoft.com/mule-user-guide/v/3.7/choice-flow-control-reference
you can take advantage of the new Mule Expression Language that allows to do the same without the need of the groovy operator