So I read a good article Advanced Configuration of the Spring MVC Framework and his final solution is a whole bunch of applicationContext-somehost.com.xml configuration files.

Hmm... it addresses the problem, but how about we just add the hostname into the properties file and append the hostname before we get it?

ok, ok, it screws with some assumptions about what a properties file is, but it deploys on as many hosts as you like, with changes limitted to this one file.


server.jdbc.user=live_user
server.jdbc.url=jdbc:postgresql://db.host.com:5432/db
server.magic.file.location=/var/magic_file
devel.jdbc.user=devel_user
devel.jdbc.url=jdbc:postgresql://devel-db.host.com:5432/db
devel.magic.file.location=c:\\var\magic_file

my.property=some other prop


<bean id="propertyConfigurer"
class="com.util.spring.HostPrecedingPropertyPlaceholderConfigurer">
<property name="location" value="classpath:config.properties" />
</bean>
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="${jdbc.driverClass}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.user}" />
<property name="password" value="${jdbc.password}" />
</bean>

package com.util.spring;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Properties;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;

/**
* HostPrecedingPropertyPlaceholderConfigurer
*
* Extends PropertyPlaceholderConfigurer to insert $hostname.property
*
* sample properties file:
*
* server.jdbc.user=live_user
* server.jdbc.url=jdbc:postgresql://db.host.com:5432/db
* server.magic.file.location=/var/magic_file
*
* devel.jdbc.user=devel_user
* devel.jdbc.url=jdbc:postgresql://devel-db.host.com:5432/db
* devel.magic.file.location=c:\\var\magic_file
*
* my.property=a property referenced through a method besides HostPrecedingPropertyPlaceholderConfigurer
*
* <bean id="propertyConfigurer"
* class="com.util.spring.HostPrecedingPropertyPlaceholderConfigurer">
* <property name="location" value="classpath:config.properties" />
* </bean>
*
* <bean id="dataSource"
* class="com.mchange.v2.c3p0.ComboPooledDataSource"
* destroy-method="close">
* <property name="driverClass" value="${jdbc.driverClass}" />
* <property name="jdbcUrl" value="${jdbc.url}" />
* <property name="user" value="${jdbc.user}" />
* <property name="password" value="${jdbc.password}" />
* </bean>
*
*
* @author Jeff Dwyer (blog)
*/
public class HostPrecedingPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {

private static Logger log = Logger.getLogger(HostPrecedingPropertyPlaceholderConfigurer.class);

protected String resolvePlaceholder(String placeholder, Properties props) {
try {
return props.getProperty(InetAddress.getLocalHost().getHostName()+"."+placeholder);
} catch (UnknownHostException e) {
log.warn(e);
return null;
}
}

}




UPDATE So I've noticed that this was a pretty popular entry & I thought I should update it to what I'm actually doing now. I've put in a little if/else & regex that replaces "HOST*" with the hostname. So now my properties still look like:

server.jdbc.url=jdbc:postgresql://db.host.com:5432/db
devel.jdbc.url=jdbc:postgresql://devel.host.com:5432/db

and they're referenced by ${HOST.jdbc.url}

This way you don't need to copy all the properties for every machine, just the HOST-specific ones. This is all working very well in production and makes scm of properties files much much easier, alleviating the confusing deploy time errors when everything seems broken and you realize someone has checked in development properties which override the correct server properties.