Using PropertyPlaceHolderConfigurer to Create a WebApp Configuration File

The problem: when developing my properties files are available on the classpath. I have many layered projects so the props files end up in a jar which gets embedded in a JAR inside the WAR. This doesn't make a very friendly config file for someone deploying the app. Essentially I want my WAR to read a config file outside the classpath, in a location determined by an environement variable. I realized I could extend Spring's PropertyPlaceHolderConfigurer to do the trick. This class and config file are below, as well as some test files.

package harschware;

import java.io.File;
import java.util.List;

import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;

import com.google.common.collect.Lists;

public class HomePropertyPlaceholderCongfigurer extends
PropertyPlaceholderConfigurer {
private String homePathEnv;
private String[] homePathLocations;

public HomePropertyPlaceholderCongfigurer(String homePathEnv,
String[] homePathLocations ) {
super();
this.homePathEnv = System.getenv(homePathEnv);
this.homePathLocations = homePathLocations;
} // end method

public void setLocations(Resource[] locations) {
List<Resource> locList = Lists.newArrayList(locations);

for (String homePathLocation : homePathLocations) {
if( homePathEnv != null ) {
Resource propFileRespource = new FileSystemResource(homePathEnv
+ File.separator + homePathLocation);
if( propFileRespource.exists() ) locList.add(propFileRespource);
} // end if
} // end for
locations = locList.toArray(locations);
super.setLocations(locations);
} // end method

} // end class



The Spring configuration file:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean class="harschware.HomePropertyPlaceholderCongfigurer">
<constructor-arg value="MY_HOME" />
<constructor-arg>
<list>
<value>home.properties</value>
</list>
</constructor-arg>
<property name="locations">
<value>classpath:test.properties</value>
</property>
</bean>

<bean id="testStr" class="java.lang.String">
<constructor-arg value="${t.x}" />
</bean>
</beans>


A Simple Test Driver:
package harschware;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestMe {

/**
* @param args
*/
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:app.xml");
System.out.println((String)ctx.getBean("testStr"));
}

}

The properties file "test.properties" (existing in the project's classpath):
t.x=Not Overridden!


The properties file "home.properties" (existing at %MY_HOME%/home.properties):
t.x=It was overidden


Running the test app would produce the output "It was overidden".

That's it!

Comments :

1
Fortifer said...
on 

Some comments about the code.

"if( homePathEnv != null ) {" can be outside the for-loop

Re-assignment of input parameter should be avoided. Better to end with: "super.setLocations(locList.toArray(locations));"

Post a Comment