Thursday, January 28, 2010

Replacing application properties with Groovy scripts

Application configuration for non-trivial applications are sometimes quite large. Apart from being large, they may also have interdependencies, so much so that you might wish you could use a dynamic script to specify the configuration.

You can use the Groovy scripting language to do the exactly same thing. Groovy has a familiar Java syntax and you can use other powerful features at runtime to specify your application configuration. Here is a 6-part approach:

Pre-condition: You need to have the Groovy JAR file in your classpath that you can get from here: http://groovy.codehaus.org/Download

1. Create a configuration class:


// filename: AppConfigStruct.java
//
public class AppConfigStruct {
// some properties - JDBC etc
//
public volatile String jdbc_driver_class = null;
public volatile String jdbc_url = null;
public volatile String username = null;
public volatile String password = null;
public volatile String validation_query = null;
public volatile String schema_name = null;
public volatile String table_name = null;
}


2. Create an interface for loading application configuration:


// filename: IAppConfigLoader.java
//
public interface IAppConfigLoader {

public abstract AppConfigStruct load();

}


3. Have the IAppConfigLoader interface implemented by the groovy config script:


// filename: AppConfigLoaderGroovyImpl.groovy
//
public class AppConfigLoaderGroovyImpl implements IAppConfigLoader {
public AppConfigStruct load() {
AppConfigStruct appConfig = new AppConfigStruct();
setAllProperties(appConfig);
return appConfig;
}
public void setAllProperties(AppConfigStruct appConfig) {
// set all properties here
// you may use more functions to divide the work
}
}


4. Now comes the meat - write a function that loads the Groovy script and parses it into a config loader:


// filename: AppConfigUtil.java
//
public class AppConfigUtil {
public static AppConfigStruct getConfigFromGroovyScript(final InputStream in)
throws IOException, IllegalAccessException, InstantiationException {
groovy.lang.GroovyClassLoader gcl = new groovy.lang.GroovyClassLoader();
Class clazz = gcl.parseClass(in);
Object aScript = clazz.newInstance();
IAppConfigLoader ifc = (IAppConfigLoader) aScript;
return ifc.load();
}
}


5. Use the above-mentioned function by loading the Groovy script from a file (useful for testing or dev mode):


// filename: AppConfigUtil.java
//
public static AppConfigStruct getConfigFromGroovyScript(final String filename)
throws
FileNotFoundException, IOException,
InstantiationException, IllegalAccessException {
final InputStream in = new FileInputStream(new File(filename));
try {
return getConfigFromGroovyScript(in);
} finally {
if (in != null) {
in.close();
}
}
}


6. You can also use the following mechanism in a servlet to load the groovy script using the servlet context classloader:


// filename: AppConfigUtil.java
//
public static AppConfigStruct getConfigFromGroovyScript(
final ServletContext servletContext,
final String groovyConfigFilename) {
// filename example -- "/WEB-INF/AppConfigLoaderProductionImpl.groovy"
final InputStream in = servletContext.getResourceAsStream(groovyConfigFile);
return getConfigFromGroovyScript(in);
}


Let me know what you think about this approach.

Disqus for Char Sequence