Mule expression variable scope - scope

What is the scope of variables in Mule expression components, and how does that relate to flow variables? I had a flow with a set-variable and was surprised to see that the value was being overwritten by an assignment in an expression-component. For example,
<flow name="HelloWorldFlow1" doc:name="HelloWorldFlow1">
<http:inbound-endpoint exchange-pattern="request-response"
host="localhost" port="9999" doc:name="HTTP"
doc:description="This endpoint receives an HTTP message." path="helloworld"/>
<set-variable variableName="asdf" value="firstvalue" doc:name="Variable"/>
<logger message="#[flowVars["asdf"]]" level="INFO" doc:name="Logger"/>
<expression-component doc:name="Expression"><![CDATA[asdf = "secondvalue";]]></expression-component>
<logger message="#[flowVars["asdf"]]" level="INFO" doc:name="Logger"/>
<expression-component doc:name="Expression"><![CDATA[qwer = "thirdvalue";]]></expression-component>
<logger message="#[flowVars["qwer"]]" level="INFO" doc:name="Logger"/>
</flow>
The output of this is:
INFO 2014-04-25 08:58:46,889 [[helloworld].connector.http.mule.default.receiver.02] org.mule.api.processor.LoggerMessageProcessor: firstvalue
INFO 2014-04-25 08:58:46,893 [[helloworld].connector.http.mule.default.receiver.02] org.mule.api.processor.LoggerMessageProcessor: secondvalue
INFO 2014-04-25 08:58:46,895 [[helloworld].connector.http.mule.default.receiver.02] org.mule.api.processor.LoggerMessageProcessor: null
If possible, can you point me to the documentation of the scoping rules? I've tried a few different searches and keep getting extraneous results.
Clarification: Within the expression-component, does Mule first check to see if there is a flow variable with a given name and then use that variable instead of creating a new one? If the expression component creates a variable, is the scope limited to just the expression component code? In http://blogs.mulesoft.org/mule-school-the-mulemessage-property-scopes-and-variables/, it says that Mule flow variables "behave like instance properties", but I can't find a definition for what an instance property is. The word scope is also not in the expression component reference page (http://www.mulesoft.org/documentation/display/current/Expression+Component+Reference).

With <set-variable you're creating a flow variable. Its scope is within flow it is declared and also sub-flows or private flow called by this flow. Think it of like as an instance variable.
Moreover, you've 4 logger statements in your flow while you're showing output of only 3 log statements. If you modify log statement to include what value you're printing, it will be less of confusion trying to figure out that print statement is for which variable like:
<logger message="Value of asdf is: #[flowVars['asdf']]" level="INFO" doc:name="Logger"/>
And you don't need to surround " arround your variable name. Other shorthand notation is to just say
<logger message="Value of asdf is: #[asdf]" level="INFO" doc:name="Logger"/>
For broader reference to scopes see this: http://blogs.mulesoft.org/mule-school-the-mulemessage-property-scopes-and-variables/
When you overwrite a variable value in a flow, initial value is overwritten by next assigned value just like a variable value assignment functions in java.
EDIT:
You're right, variables created by <set-variable> can be re-assigned with expression component but variables created inside <expression-component> doesn't have scope out side that block. Sorry I don't have links to back up with, this is based on my experiment.

Apart from what #Charu Khurana explained, I can see in our application that flow variables can be used by the parent flow. So, if you call a child flow from a parent flow(with <flow-ref> for example) and use <set-variable> inside, you will have access to these vars in your parent flow.

Related

Mule 3 retrieving the placeholder value dynamically

I have a use-case that I need to retrieve the value from my properties file but that key should be derived dynamically from my query params.
How to handle this in MEL or Groovy? I am aware it is possible in DW.
Http request
https://localhost:9898/getStore?search=customer.weststore.name
And my placeholders are -
file.properties
customer.weststore.name=TESTING
customer.eaststore.name=IRERRER
So the way I need to access something like this
<set-variable variableName="westDetail" value="#[message.inboundProperites['customer.weststore.name']" doc:name="Variable"/>
<logger message="${westDetail}" level="INFO" /> --> Failed as no placeholder available
When I tried the above it's failing due to no placeholder as "westDetail" available whereas I need the fetch that particular key from the properties file.
This is something related to this article - https://help.mulesoft.com/s/question/0D52T00004mXTQUSA4/dynamically-read-property-values-from-a-properties-file-in-mule but the only solution provided with DW not MEL or Groovy.
How anyone advises, Is it possible?
I understand that the problem is that you want to query the properties by a key that is obtained at execution.
You are doing it incorrectly. ${} is for evaluating the value of a property, which is done at initialization time of the application. You missed that get the actual value in the set-variable.
#[] is for executing a MEL expression, which happens at execution time. flowVars.westDetail is a MEL expression that returns the value of flow variable westDetail. You can't use a MEL expression to evaluate the property placeholder ${}, because they are evaluated at different times.
A solution is to use a Spring bean to store the properties, instead of a configuration properties placeholder. Then you can assign it to a flow variable and access it like a map.
Example:
<spring:beans>
<spring:bean id="myProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<spring:property name="location" value="classpath:items.properties"/>
</spring:bean>
</spring:beans>
<flow name="myFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/" doc:name="HTTP"/>
<set-variable value="#[app.registry.myProperties]" variableName="props"></set-variable>
<logger message="a=#[flowVars.props['a']]" level="INFO"/>
</flow>
items.properties:
a=1
b=2
c=3
Output:
a=1

Can SpEL in Spring Integration Router use Java's String class methods

This is an extension question to How to use SpEL to read payload and header content in a Spring Integration Router
Technologies in my project
Spring Boot 2
Spring Integration (XML style)
Java 8
Tomcat 9.x/Liberty 19.0.0.1
As a part of my Spring Integration project (REST API with an inbound-http-gateway, that takes an XML input and produces an XML output), this is the setup for my question:
There is a Builder-pattern-based Java object (say, MyPOJO) that is the payload in the flow.
MyPOJO has a String property/instance variable (say, String response) along with a getter and setter.
Somewhere in the flow, MyPOJO gets built and response gets set.
Inside response, there is a keyword/specific piece of text that will determine the further course of the flow.
This said, is it possible to write a Router (using XML configuration) that can check if the response inside Message<MyPOJO> contains that keyword/specific piece of text to determine where to go next?
Illustratively, something like this:
<int:router input-channel="inputChannel" expression="payload.getResponse().contains("keyword")">
<int:mapping value="true" channel="oneRoute"/>
<int:mapping value="false" channel="anotherRoute"/>
</int:router>
When I do this and launch the application, the error is:
nested exception is org.xml.sax.SAXParseException; lineNumber: 44; columnNumber: 98; Element type "int:router" must be followed by either attribute specifications, ">" or "/>"
Specifically speaking, the expression="payload.getResponse().contains("keyword")" part seems to be having an issue getting resolved and this could be something to do with the quotation marks around the keyword
Any help on this is greatly appreciated.
Sincerely,
Bharath
OK. I see you have an XML syntax error. The fix is like this:
expression="payload.getResponse().contains('keyword')"
The keyword is in single quotes, not double.
This is definitely how SpEL works: when you would like to specify a literal in the expression, you need to use single quotes: https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#expressions-evaluation

How to set payload as constructor-arg value in service-activator

I've started with SI and kind of stuck right now as we want to use SI in one of our existing project avoiding changes where we can.
A bean which we would be using as a service activator accepts an constructor argument of a java object.
that object is in the payload but then I'm unable to set it using inner bean usage of service-activator
<service-activator input-channel="ADMIN_TEST_CONNECTION" method="testConnection">
<beans:bean class="mypackage.request.AdminRequestProcessor">
<beans:constructor-arg value="payload"/>
</beans:bean>
</service-activator>
it's complaining about Could not convert argument value of type [java.lang.String] to required type.
Please help in how to access payload and set it as an constructor argument.
If I go via non- constructor arg route and change existing java object then it works with this call in the service activator
expression="#bean.testConnection(payload)"/>
but I don't wish you to change the existing java code until there is no other way.
I think you don't have choice unless change something or add code around existing.
Service-Activator performs its functionality against each incoming message in the input-channel. And that functionality is exactly method invocation where Message is used as a context for method arguments.
Not sure what you are going to do with that payload, but that doesn't look correct to use statefull object like your AdminRequestProcessor. Just don't forget that you may have many incoming message, but service-activator should be consistent.
Plus don't forget that <beans:bean> is singleton, so your AdminRequestProcessor is instantiated only once.
Looking to your sample I'd suggest something like this:
expression="new AdminRequestProcessor(payload).testConnection()"/>
If you really don't want to change anything in your code.
Everything rest you can find in the Reference Manual.

How can i assign Mule Variable Value to Property Key -Value lookup?

I want to find out the careerName from variable
I want to use that CareerName as Property Key. Example. If careerName came-up as apple, I have value setup against that key apple=ST\*214|ST\*210.
I have following line of code for Mule Choice Expression, which i tried with but i am not getting success here.
mule-esb.test1.properties
ftp.inbound.carriers.path='CareerName1/InBound/','CareerName2/InBound/','CareerName3/InBound','CareerName4/InBound/','apple/InBound/'
CareerName1=ST\*214|ST\*210
CareerName2=ST\*214|ST\*210
CareerName3=.\ST.214.\
CareerName4=ST\*214
apple=ST\*214
<context:property-placeholder location="mule-esb.${mule.env}.properties" />
<when expression="import java.util.regex.Pattern;Pattern p = Pattern.compile('${'+message.getInvocationProperty('careerName')+'}');return p.matcher(payload.toString()).find();" evaluator="groovy">
Looking for some alternatives or solution on this script.
MEL has extensive regex support, you shouldn't need to use Groovy. See: http://www.mulesoft.org/documentation/display/current/Mule+Expression+Language+Tips#MuleExpressionLanguageTips-RegexSupport
You need to load your properties in an Map that you can query from the registry but also use in the property placeholder resolver. So do this:
<util:properties id="configProperties"
location="classpath:mule-esb.${mule.env}.properties" />
<context:property-placeholder properties-ref="configProperties" />
With this in place, the following should work:
<when expression="#[regex(app.registry.configProperties[careerName])]">
define a spring bean globally configuring the key value pair properties for the bean.
the bean definition should accept the spring properties and a method which accept the key and returns the corresponding value.
sample bean definition as follows
<spring:bean id="entityMapper" name="entityMapper" class="com.xx.xx.commons.ClassNameXX">
<spring:property name="entities">
<spring:props>
<spring:prop key="CareerName1">${CareerName1}</spring:prop>
.
.
</spring:props>
</spring:property>
</spring:bean>
so in the flow level you can get value from bean with below expression.
#[app.registry.entityMapper.getEntity(message.getInvocationProperty('careerName'))]
where entityMapper will be the bean name and getEntity is the method defined in bean which accept the careerName and return the corresponding value.
hope this helps.
Dynamically you cant access the value directly from context placeholder.

How to Configure Log4Net to Enable Logging for a Particular Class

Given an assembly with 2 classes, Foo and Bar, via the configuration file, how to I enable logging at the Info Level for Foo, and the Warning level for Bar?
What configuration you use, depends on how the Logger is created. The basic configuration looks like this:
<logger name="(INSERT LOGGER NAME HERE)">
<level value="(WHATEVER LOG LEVEL TO APPLY FOR THIS PARTICULAR LOGGER)" />
</logger>
What determines your Logger Name is how you create it.
LogManager.GetCurrentClassLogger() // The name will be "namespace.name" of the current class.
LogManager.GetLogger<T>() // The name will be "namespace.name" of the Type T.
LogManager.GetLogger(Type type) // The name will be "namespace.name" of the type.
LogManager.GetLogger(string name) // The name will be name.
So if you have a particular process that you want to log in multiple classes / files, define the name of the process and use the string overload.
If you want to be able to turn on logging for a single class, use one of the other overloads.

Resources