How is the following property resolved ${sys:foo} by Log4j2 - spring

I am looking at a log4j2.xml configuration from Spring Boot and see the following configuration (unimportant parts removed):
<Property name="PID">????</Property>
<Property name="LOG_EXCEPTION_CONVERSION_WORD">%xwEx</Property>
<Property name="LOG_LEVEL_PATTERN">%5p</Property>
<Property name="LOG_PATTERN">
... %clr{${LOG_LEVEL_PATTERN}} %clr{${sys:PID}}{magenta}
... %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}
</Property>
Lets take a look: ${LOG_LEVEL_PATTERN} is clear, it resolves to the property defined in the line above. But The next two variable expansions have a sys: prefixed, what exactly does that do?
More importantly who does the resolution of these variables (in particular sys:)? Is it Log4j2 specific? Is this expansion done by Maven or maybe the Spring Framework which I am using?

Take a look at org.apache.logging.log4j.core.lookup. In particular the Interpolator class and the SystemPropertiesLookup class.
The Interpolator will attempt to use the SystemPropertiesLookup which returns
return System.getProperty(key);
If the result is null it will then try a default lookup, which is a MapLookup.
if (map == null) {
return null;
}
return map.get(key);
This map is the map defined by the properties section in the config.
TLDR
The lookups are handled by log4j2 core. First it will try and get the system property. if no system property exists it will then look for a property defined in the properties section of your config.

Related

How to get set elements in the same sequence as in a Spring bean definition

I have a lot of bean definitions that look similar to this
<bean id="TransformationMapOrganization " class="com.artifact_software.adt.plugin.transformation.RemoveColumnsTransformationImpl">
<property name="pluginId" value="Remove Division, Department, and Cost Code" />
<property name="dataStoreName" value="person_data"/>
<property name="columnNames">
<set>
<value>Division</value>
<value>Dept Code</value>
<value>Cost Code</value>
</set>
</property>
</bean>
In the code, the columnNames are defined as:
protected List<String> columnNames;
It appears that erroneous duplicate values are ignored rather causing an error which is good. I hope that I can count on that since it does make life easier!
What set implementation will Spring use?
What is the correct way to iterate through columnNames to get the columnNames in the same sequence as they are specified in the bean?
You can set the implementation class via <set set-class="com.my.SetImpl" />, (see current doc). (com.my.SetImpl must implement java.util.Set)
alternatively: define targetClass on your SetFactoryBean...
If omit, current spring, will use java.util.LinkedHashSet.
More correct, reliable & future-safe it would be to map columnNames as java.util.Set not as a List (+ to use set-class).
If no set-class attribute is supplied, the container chooses a Set implementation.
(in your case,) Obviously spring manages to convert from set to list "smoothly" ("by hand" it's also easy done thx to api design). Spring (seems to) also preserves you distinct entries, LinkedHashSet implementation additionally guarantees/should "preserve order"...
Your Bean definition and field names are different. Change
<property name="ColumnNames">
to
<property name="columnNames">

Spring property value - res: URI

I've been using spring for years but can't seem to find documentation on this one. If I have a spring bean configured like this:
<bean id="myBeanInstance" class="org.mybean">
<property name="path" value="res:a-string-goes-here"/>
</bean>
Is the value being interpreted as purely a string? How does 'res:' affect anything and where is it being interpreted? Any pointers to the appropriate docs would be fantastic.
Thanks!
Yes, the value is interpreted purely as string...
Unless you have a BeanFactoryPostProcessor, such as weirdly configured PropertyPlaceholderConfigurer or some custom BeanFactoryPostProcessor to take care of such values.
Note also, that since Spring 3 the ':' is the default separator for default property values, i.e. if you have PropertyPlaceholderConfigurer with default setting, the value "${res:whatever}" would be treated as a property 'res' with default value 'whatever'.

Mule ESB 3.4 Context property

How can one access the properties loaded by context:place-holder in a scripting component other than having to use ${property-name}? I want to get to the object that holds these key value pairs. Something like context.getProperty("property-name").
Spring property placeholders are resolved at configuration time and not stored anywhere, so they cant be loaded afterwards.
If you need to store it you can always inject them into a bean and retrieve that from the registry.
Basically all you need to do is to declare your bean:
<spring:bean class="your.Bean" name="yourBean" >
<spring:property name="yourBeanAttribute" value="${somePlaceHolder}" />
</spring:bean>
and then you can retrieve it, and the somePlaceHolder value from the registry from within a scripting component/transformer:
<scripting:transformer doc:name="Script">
<scripting:script engine="Groovy">
<scripting:text><![CDATA[
def val = muleContext.getRegistry().lookupObject('yourBean').getYourBeanAttribute()
]]></scripting:text>
</scripting:script>
</scripting:transformer>
HTH

Property Placeholder for Imports/Bean Refs

Can I use a property loaded from property-placeholder to make a context import dynamic?
<context:property-placeholder location="classpath*:/enterprise.properties"/>
<import resource="classpath*:/Fsb${jdbc.ctxType?:Jdbc}-context.xml"/>
Properties File
jdbc.ctxType=JTA
So this way I could change the type of context file that is loaded based on a property.
Also, can I do the same thing to make a bean ref name dynamic?
<bean id="personBusinessService" class="com.foo.PersonBusinessServiceImpl"
p:personUidDataService-ref="personUidDataService${personUidDataService.sib?:Api}"
p:identifierLookupSearchService-ref="identifierLookupSearchService${identifierLookupSearchService.sib?:Api}"
p:contactPointBusinessService-ref="contactPointBusinessService${contactPointBusinessService.sib?:Api}"
/>
Properties File
personUidDataService.sib=Stub
Jay
--------------------Update example of property for ref-------------------------
I created a property file with the following entry:
addressLookupSearchService.sib=DaoMock
Then I have the following configuration in a Spring Context File:
<context:property-placeholder location="classpath*:/simple.properties"/>
<!-- EntityManager will be injected into DAO by JPA annotations -->
<bean id="addressSearchDao" class="com.foo.AddressSearchDaoImpl"/>
<bean id="addressSearchDaoMock" class="com.foo.MockAddressSearchDaoImpl"/>
<bean id="addressLookupSearchService" class="com.foo.AddressLookupSearchServiceImpl"
p:baseDao-ref="addressSearch${addressLookupSearchService.sib?:Dao}"/>
And addressSearch${addressLookupSearchService.sib?:Dao} doesn't work, it always defaults to
the bean id of addressSearchDao even if my property says it should set to addressSearchDaoMock.
Any thoughts as to what I am doing wrong?
This is a similar question to this one.
Imports are resolved before bean (property-placeholder) creation, so you can not use the property file to define properties which you want to use in an import statement. In this case you have to set the property as system property (-Djdbc.ctxType=JTA) (have a look at the link - paragraph Note).
But using the property file properties in bean definitions works fine - that's what they are for :-)
Update: Since Spring 3.1 the Unified Property Management allows to use properties even in imports (thanks #Jay Blanton for mentioning this in the comments).
Yes, you can. You can use expressions in imports and injections.

reading a dynamic property list into a spring managed bean

I've been searching but cannot find these steps. I hope I'm missing something obvious.
I have a properties file with the following contents:
machines=A,B
I have another file like that but having a different number of members in the machines element like this:
machines=B,C,D
My question is how do I load this variable-length machines variable into a bean in my spring config in a generic way?
something like this:
<property name="machines" value="${machines}"/>
where machines is an array or list in my java code. I can define it however I want if I can figure out how to do this.
Basically I'd rather have spring do the parsing and stick each value into a list element instead of me having to write something that reads in the full machines string and do the parsing myself (with the comma delimiter) to put each value into an array or list. Is there an easy way to do this that I'm missing?
You may want to take a look at Spring's StringUtils class. It has a number of useful methods to convert a comma separated list to a Set or a String array. You can use any of these utility methods, using Spring's factory-method framework, to inject a parsed value into your bean. Here is an example:
<property name="machines">
<bean class="org.springframework.util.StringUtils" factory-method="commaDelimitedListToSet">
<constructor-arg type="java.lang.String" value="${machines}"/>
</bean>
</property>
In this example, the value for 'machines' is loaded from the properties file.
If an existing utility method does not meet your needs, it is pretty straightforward to create your own. This technique allows you to execute any static utility method.
Spring EL makes easier.
Java:
List <String> machines;
Context:
<property name="machines" value="#{T(java.util.Arrays).asList('${machines}')}"/>
If you make the property "machines" a String array, then spring will do it automatically for you
machines=B,C,D
<property name="machines" value="${machines}"/>
public void setMachines(String[] test) {
Since Spring 3.0, it is also possible to read in the list of values using the #Value annotation.
Property file:
machines=B,C,D
Java code:
import org.springframework.beans.factory.annotation.Value;
#Value("#{'${machines}'.split(',')}")
private List<String> machines;
You can inject the values to the list directly without boilerplate code.(Spring 3.1+)
#Value("${machines}")
private List<String> machines;
for the key "machines=B,C,D" in the properties file by creating following two instance in your configuration.
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean
public ConversionService conversionService() {
return new DefaultConversionService();
}
Those will cover all the separate based split and whitespace trim as well.

Resources