We had a similar configuration requirement when deploying a webapp for different developers, and on Amazon's EC2: how do we separate configuration from the binary code? In my experience, JNDI is too complex, and varies too much between containers to be used. Also, hand-editing XML is very susceptible to syntax errors, so was the idea was thrown out. We resolved this with a design based on a few rules:
1) only simple name=value entries should be used
2) new configurations should be loadable by changing only one parameter
3) our WAR binary must be reconfigurable w/o repackaging it
4) sensitive parameters (passwords) will never be packaged in the binary
Using .properties files for all configuration, and using System.getProperty("domain");
to load the appropriate properties files, we were able to meet the requirements. However, the system property does not point to a file URL, instead we created a concept we call "domain" to specify the configuration to use. The location of the configuration is always:
$HOME/appName/config/$DOMAIN.properties
.
So if I want to run my app using my own configuration, I start the app by setting the domain to my name:
-Ddomain=jason
on startup, and the app loads the file:
/home/jason/appName/config/jason.properties
This lets developers share configurations so we can recreate the same state of the app for testing and deployment without recompiling or repackaging. The domain value is then used to load .properties from a standard location, outside of the bundled WAR.
I can completely recreate the production environment on my workstation by using the production configuration like:
-Ddomain=ec2
which would load:
/home/jason/appName/config/ec2.properties
This setup allows us to do have dev/QA/release cycles with exactly -one- set of compiled binaries, using different configurations in each environment. There's no risk of having passwords/etc bundled in the binaries, and people can share their configurations to recreate issues that we're seeing.