Choice flow control component fails in Mule ESB - mule

i have a choice flow control component that uses an expression as follows:
<choice>
<when expression="${LoggingFlag} == YES">SOME CODE</when>
<otherwise>SOME OTHER CODE</otherwise>
</choice>
Here LoggingFlag used is a key-value pair defined in the app.properties file.
LoggingFlag=NO
when i run the code i see the following error:
Execution of the expression "NO == YES" failed. (org.mule.api.expression.ExpressionRuntimeException). Message payload is of type: String
Exception stack is:
1. [Error: unresolvable property or identifier: NO]
[Near : {... NO == YES ....}]
Can someone tell me what is the reason behind this issue?

This error occurs due to Mule not being able to resolve the type of value, set to LoggingFlag while comparing it in choice.
For this you need to explicitly change the type to string, so that Mule can compare the two easily.
For that you need to use:
<choice>
<when expression="'${LoggingFlag}' == 'YES'">SOME CODE</when>
<otherwise>SOME OTHER CODE</otherwise>
</choice>

You need to enclose the variables in when expression within single quotes ' '
<choice doc:name="Choice">
<when expression="'${LoggingFlag}' == 'YES'"><set-payload value="payload 1" doc:name="Set Payload"/></when>
<otherwise><set-payload value="payload 2" doc:name="Set Payload"/></otherwise>
</choice>

You can even try by reading the property value and storing it in a variable and then comparing the variable value with the string in choice component as follows:
<set-variable variableName="SetLoggingFlag" value="${LoggingFlag}" doc:name="SetLoggingFlag"/>
<choice>
<when expression="#[flowVars.SetLoggingFlag=='YES']">SOME CODE</when>
<otherwise>SOME OTHER CODE</otherwise>
</choice>
Hope this helps you!

Related

msbuild task conditional operators in parameter value

Is there any way how to use conditional variables as parameters when calling MSBuild tasks?
for example, if we have text being string argument in MySampleTask msbuild task:
<MySampleTask text="if a not empty ? a : b" />
How to pass text string variable if we may have 2 local string variables a and b? How to achieve behavior in above code?
I'm not aware of such operator, but what you want is equivalent to
<MySampleTask text="$(a)" Condition="'$(a)' != ''" />
<MySampleTask text="$(b)" Condition="'$(a)' == ''" />
Or, same principle but applied to a property first; probably the most 'standard' way:
<PropertyGroup>
<a Condition="'$(a)' == ''">$(b)</a>
</PropertyGroup>
<MySampleTask text="$(a)" />

In Mule 4 how do I get error handling to use the payload?

I am using Mule 4 to make a flow and on the error handling I want it to transform the message to something that uses the existing payload.
My code is
transactionNotification: {
"Testout": "Band",
"errorNotification": p("api.name"),
"transactionCode": p("notification.errorCode"),
"transactionStatus": p("notification.error"),
remark: {
messageCode: p("notification.messageCode"),
messageText: payload
}
}
and I get the error
Scripting language error on expression '%dw 2.0 output
application/json
transactionNotification: {
"Testout": "B...'. Reason: Unable to resolve reference of payload..
The same code seems to work in the normal flow and the error goes away
when I delete payload.
I managed to achieve this using a "Set Variable" to a java object.
Name: payloadString
Value: #[payload]
MIME Type
application/java
I can then use it like you
{
"Testout": "Band",
"errorNotification": p("api.name"),
"transactionCode": p("notification.errorCode"),
"transactionStatus": p("notification.error"),
remark: {
messageCode: p("notification.messageCode"),
messageText: (vars.payloadString as String)
}
}

Is it possible to modify the original collection in foreach inside loop?

I want to mimick this:
for (int i = 0; i < items.getTotal(); i++) {
// ....
items = // new items get assigned.
}
Is it possible with foreach component?
I think you will better of using a collection-splitter and a collection-aggregator which will modify the original payload.
<collection-splitter />
<set-payload value="do something" />
<collection-aggregator />
Alternatively, if you must use foreach, you could use a flowVar to keep track of the items and the set the payload to the flowVar after the foreach:
<set-variable variableName="items" value="#[[]]" />
<foreach>
<set-payload value="do something" />
<expression-component>flowVars.items.add(payload)</expression-component>
</foreach>
<set-payload value="#[flowVars.items]" />
A workaround:
Outside the foreach:
Set a session variable X to the content of the linkedlist thru which
you want to loop.
All my MS JDBC 4.1 stored procedure calls return 1-n hashmaps with key=resultSetx and value of a linkedlist. Each occurrence in the linkedlist is another hashmap containing a 1 row's worth of resultset pairs (key=value) - so we run into this a lot.
At the foreach top level:
Set the payload collection reference to the payload which contains
the linkedlist. Reminder: (The default counter flowVar starts
at 1. Linkedlist offsets begin at 0.)
Inside the foreach:
Set another variable (ctr-1) equal to counter - 1; if you don't it
can make some ugly and difficult MEL with those counter -1
references).
Point your list inserts at the session variable X linkedlist.
After completion of foreach:
- Don't forget to remove the redundant list it wastes space.
Cheers-MPC:-)

Is there a while loop in Camel?

Is there an idea of a while loop in Camel?
We are using Camel for doing batch processing (not really the remit of an ESB I know). I want to keep checking on the status of something else whilst I am processing messages in the ESB. I can only find a loop that loops for a defined number of times, i.e. for testing or a quartz timer that will check every x seconds. Neither of these are really suitable.
Any suggestions, or am I asking for something simply outside of the remit of an ESB?
What about doing something like this:
<camelContext id="myContext">
<route id ="initializer">
<!--This will be created only once -->
<from uri="timer://foo?repeatCount=1"/>
<to uri="seda:mySedaQueue"/>
</route>
<route id ="myRoute">
<from uri="seda:mySedaQueue"/>
<choice>
<when>
<simple>{your condition if you want to continue}</simple>
...
<to uri="seda:mySedaQueue" />
</when>
<otherwise>
...
</otherwise>
</choice>
</route>
</camelContext>
How about the camel timer:?
E.g.
from("timer://foo?fixedRate=true&period=1000")
.to("bean:myBean?method=someMethodName");
Reference: Camel Timer Component
Try using DynamicRouter.
It uses an Expression class to determine the next route to dispatch the exchange. If the expression returns null it means that it will stop routing.
This way you can evaluate the exchange contents and continue routing to the same route until you decide is time to stop, and then return null.
from("direct:start")
.dynamicRouter(new Expression() {
#Override
public <T> T evaluate(Exchange exchange, Class<T> type) {
if (<your condition>) return (T) "direct:whileRoute";
return null;
}
})
.to("mock:finish");
from("direct:whileRoute")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
// Do whatever you want
}
});

originalPayload not the same as message.originalPayload in groovy scripts

I found that originalPayload does not do the same as message.originalPayload in groovy expressions. That is, the following transformers do not do the same thing:
with originalPayload:
<expression-transformer evaluator="groovy" expression="originalPayload" />
with message.originalPayload:
<expression-transformer evaluator="groovy" expression="message.originalPayload" />
The following mule configuration and test case can be used to reproduce the issue:
<mule ...>
<flow name="test">
<vm:inbound-endpoint name="test.Name" path="test.Path"
exchange-pattern="request-response" />
<expression-transformer evaluator="string" expression="bar" />
<expression-transformer evaluator="groovy" expression="originalPayload" />
<!-- or alternatively -->
<!-- <expression-transformer evaluator="groovy" expression="message.originalPayload" /> -->
</flow>
</mule>
The test case can be:
#Test
public void transformers() throws MuleException {
final MuleClient client = muleContext.getClient();
final MuleMessage reply = client.send("vm://test.Path", 1, null, RECEIVE_TIMEOUT);
assertEquals(1, reply.getPayload());
}
The alternative with message.originalPayload works as expected. The one with originalPayload does not and the following exception is shown in the logs:
Exception stack is:
1. Expression Evaluator "groovy" with expression "originalPayload" returned null
but a value was required. (org.mule.api.expression.RequiredValue Exception)
What could I be doing wrong?
Thanks.
The problem is that expression-transformer and scripting:transformer use a different set of bindings than the one used by a scripting:component, and this because they call a different method in org.mule.module.scripting.component.Scriptable.
Moreover, when originalPayload gets bound, it is with the wrong value:
bindings.put("originalPayload", event.getMessage().getPayload());
Hence: MULE-6215
Following the Scripting Module Reference, they should be the same.
Also, if you take a look to org.mule.module.scripting.component.Scriptable in the scripting module, you will find that "originalPayload" is message.getPayload.
Can you post a small project reproducing the error?
public void populateBindings(Bindings bindings, MuleMessage message)
{
populateDefaultBindings(bindings);
if (message == null)
{
message = new DefaultMuleMessage(NullPayload.getInstance(), muleContext);
}
bindings.put("message", message);
//This will get overwritten if populateBindings(Bindings bindings, MuleEvent event) is called
//and not this method directly.
bindings.put("payload", message.getPayload());
//For backward compatability
bindings.put("src", message.getPayload());
}
public void populateBindings(Bindings bindings, MuleEvent event)
{
populateBindings(bindings, event.getMessage());
bindings.put("originalPayload", event.getMessage().getPayload());
bindings.put("payload", event.getMessage().getPayload());
bindings.put("eventContext", new DefaultMuleEventContext(event));
bindings.put("id", event.getId());
bindings.put("flowConstruct", event.getFlowConstruct());
if (event.getFlowConstruct() instanceof Service)
{
bindings.put("service", event.getFlowConstruct());
}
}