Saturday, December 18, 2010

Grails and external configuration - the easy way

Hi folks!

This time we're going to work towards the ability to change application's configuration after deployment. In spring what you usually do is allow for loading some settings from a configuration file first prior to setting the defaults. This way once a particular key has been set in the override it's not going to be overridden by the defaults in your applicationContext.xml or beans.xml (however you wanna call it).

In Grails thanks to the existence of another mechanism we can do it differently. We can instruct Grails to load overrides if they have been declared in either the system properties for currently running process (using the -D notation in JAVA_OPTS) or plain in environment options.

The first option is dead simple. What you need to do is to go to your conf/Config.groovy and uncomment the following lines near the top of the file (at least in the original one):
if(System.properties["${appName}.config.location"]) {
grails.config.locations << "file:" + System.properties["${appName}.config.location"]
}

Unfortunately when you do that and set the proper setting during the invocation of java process that started your application (that'd be Tomcat) you'll be presented with an error message like this:
log4j:ERROR Error initializing log4j: No signature of method: 
groovy.util.ConfigObject.leftShift() is applicable for argument
types: (java.lang.String) values: [file:]
Possible solutions: leftShift(java.util.Map$Entry), leftShift(java.util.Map)
groovy.lang.MissingMethodException: No signature of method:
groovy.util.ConfigObject.leftShift() is applicable for argument types:
(java.lang.String) values: [file:]
Possible solutions: leftShift(java.util.Map$Entry), leftShift(java.util.Map)
at Config.run(Config.groovy:17)
2010-12-18 22:30:46 org.apache.catalina.core.StandardContext start
SEVERE: Error listenerStart
2010-12-18 22:30:46 org.apache.catalina.core.StandardContext start
SEVERE: Context [/] startup failed due to previous errors

This is due to the fact that the grails.config.locations element is not set by default. To fix this simply add the following line just before the the code you've just uncommented:

grails.config.locations = []

Once that's done you're able to specify the additional config location in JAVA_OPTS and live is good :)

The other option is to change the predefined code to look for an environment variable instead:

if(System.getenv()["${appName}.config.location"]) {
grails.config.locations << "file:" + System.getenv()["${appName}.config.location"]
}

This way instead of looking for parameters specified via the -D option while invoking the Java virtual machine it'll look for an environment variable.

Surely you'll find more ways to specify the config file location. The beauty of this solution lies in diversity :)

I hope it'll help someone!

No comments: