code,prettyprint
public class ApplicationConfigurer extends PropertyPlaceholderConfigurer {
private final static Logger theLogger = Logger.getLogger(ApplicationConfigurer.class);
public static final String APPLICATION_HOME_PROPERTY = "application.home";
public static final String CUSTOM_APPLICATIONS_FILE = "applications.xml";
public static final String GENERATED_APPLICATIONS_FILE = "generated.applications.xml";
private static final String APPLICATION_HOME = ".mycompany"+File.separatorChar+"myapp";
private static final String APPLICATION_PROPERTIES_FILE = "/myapp.properties";
private static final String SAMPLE_APPLICATIONS_FILE = "/com/mycompany/conf/applications.sample.xml";
public ApplicationConfigurator() {
// output generic version data
theLogger.info(Version.getVersion());
theLogger.info("(c) MyCompany 2007");
String fultyHome = null;
// search for application.properties file
InputStream in = this.getClass().getResourceAsStream(APPLICATION_PROPERTIES_FILE);
Properties props = new Properties();
if (in != null) {
try {
props.load(in);
setProperties(props);
fultyHome = props.getProperty(APPLICATION_HOME_PROPERTY);
} catch (IOException e) {
in = null;
theLogger.warn("Unable to read properties file " + APPLICATION_PROPERTIES_FILE, e);
}
}
if (in == null) { // search for system property
fultyHome = System.getProperty(APPLICATION_HOME_PROPERTY);
if (fultyHome == null) { // create default home
fultyHome = System.getProperty("user.home") + File.separator + APPLICATION_HOME;
}
props.put(APPLICATION_HOME_PROPERTY, fultyHome);
setProperties(props);
}
theLogger.info("Using APPLICATION_HOME : " + fultyHome);
File homeDir = new File(fultyHome);
createDefaults(homeDir);
}
private void createDefaults(File aHome) {
if (!aHome.exists()) {
theLogger.info(aHome + " does not exist. Creating default files");
aHome.mkdirs();
}
File appFile = new File(aHome, CUSTOM_APPLICATIONS_FILE);
if (!appFile.exists()) {
theLogger.info("Configuration "+ CUSTOM_APPLICATIONS_FILE +" does not exist. Using defaults file.");
theLogger.info("Please edit " + appFile.getAbsolutePath() + " then restart the application");
URL url = this.getClass().getResource(SAMPLE_APPLICATIONS_FILE);
File src = new File(url.getFile());
copySampleFile(appFile, src);
copySampleFile(new File(aHome, GENERATED_APPLICATIONS_FILE),src);
}
}
private void copySampleFile(File aAppFile, File aSrc) {
try {
FileOutputStream out = new FileOutputStream(aAppFile);
FileInputStream in = new FileInputStream(aSrc);
in.getChannel().transferTo(0, aSrc.length(), out.getChannel());
in.close();
out.close();
} catch (IOException e) {
theLogger.error("Unable to copy default applications file",e);
}
}
}
-------------------------------------------------------------------------------------------------------
That’s all ! This class creates a single property called _application.home_ that may be used in your Spring configuration file. As I said before, you could read more that one property and create a whole set of properties to be used in your Spring configuration file, but as I also split my Spring configuration files and the lack of property exports to child contexts, the only property I export is the application home, so that *other beans can programatically create Spring contexts*.
[[]]
Conclusion
----------
This post showed you that you could, at level design, avoid some lacks to the Java web application frameworks which makes it rather complex to separate configuration data from the application itself. This is a low cost implementation which demonstrates that it is not necessarily costly to think about it, and that it is, to my mind, something that *should always be done* because it *simplifies maintenance*.