Loading...

Friday, February 4, 2011

Grails Goodness: One WAR to Rule Them All (Part 2)

In a previous post we learned how easy it is to have just one WAR with different configuration settings for different environments. All configuration settings are part of the application code and if we want to change a value we must rebuild the WAR file again. But what if we want to set configuration options for different environments outside of the application code? So if we want to set a configuration property for a specific environment we don't have to rebuild the WAR file? In this post we learn how to achieve this for a Grails application.

In Grails we can add extra configuration files by setting the grails.config.locations property in grails-app/conf/Config.groovy. We can assign a list of files available in the classpath or file system. Besides Groovy configuration scripts we can also define plain old Java property files. If we start with a new fresh Grails application we can see at the top of grails-app/conf/Config.groovy the code for this functionality in a comment block. To define the location of our environment specific configuration file per application server we read in the file location from a system property value. So we leave the placement of the configuration file up to the administrators of the application server, because we don't want to hard-code the file location in our application code. At the top of the grails-app/conf/Config.groovy file we set the value of grails.config.locations:

// File: grails-app/conf/Config.groovy
def CONFIG_LOCATION_SYS_PROPERTY = 'sample.app.config.file'
if (System.properties[CONFIG_LOCATION_SYS_PROPERTY]) {
    grails.config.locations = ["file:" + System.properties[CONFIG_LOCATION_SYS_PROPERTY]]
}

...

We change our index view and add extra code to show the value of a new configuration property: nodeName. The value for this property needs to be defined in the configuration file we assign via the system property sample.app.config.location.

<%-- File: grails-app/views/index.gsp --%>

...

<h1>Application Status</h1>
<ul>
    <li>Running mode: ${grailsApplication.config.runningMode}</li>
    <li>Node: ${grailsApplication.config.nodeName}</li>
    <li>App version: <g:meta name="app.version"></g:meta></li>
    <li>Grails version: <g:meta name="app.grails.version"></g:meta></li>
    <li>Groovy version: ${org.codehaus.groovy.runtime.InvokerHelper.getVersion()}</li>
    <li>JVM version: ${System.getProperty('java.version')}</li>
    <li>Controllers: ${grailsApplication.controllerClasses.size()}</li>
    <li>Domains: ${grailsApplication.domainClasses.size()}</li>
    <li>Services: ${grailsApplication.serviceClasses.size()}</li>
    <li>Tag Libraries: ${grailsApplication.tagLibClasses.size()}</li>
</ul>

...

Our application code changes are done and we can package the application as WAR file:

$ grails war

Next we create a Groovy script which sets the property nodeName. For each application server or environment we create a file. For example we create a file sample-config.groovy for the system test Tomcat instance of our previous post:

// File sample-config.groovy
nodeName = 'System Test'

Before we start our application servers we must set the system property sample.app.config.file. We must reference our Groovy script which set the nodeName property.

$ export CATALINA_OPTS="-Dsample.app.config.file=sample-config.groovy"

After we have defined the correct value we can install our single WAR file to the three Tomcat instances and start them. If we then open the index page of our application we can see in the left column the value or our configuration property nodeName:

We see the correct value for each environment. Grails has built-in support for adding external configuration files to the application configuration. This makes it very easy to set configuration properties for separate environments and their values can be changed without building a new WAR file.

In the following post we learn how to change the display name in the web.xml containing the application name and version.

2 comments:

Gary said...

sorry for hitting an old post but curious.. any idea how to run 2 apps on tomcat with different environments? can't simple set the -Dgrails.env variable as this will be used by both..

Hubert Klein Ikkink said...

@Gary: true, the -Dgrails.env setting will work for a single Tomcat instance and if two apps are deployed they will share the same environment. You could use the approach mentions in this blog post and use an external configuration file. But for each application you must include the app name in the name of the configuration file. So you could specify the base configuration file name using -Dapp.config.file and in Config.groovy you could do something like: grails.config.locations = [file: + System.properties['app.config.file'] + appName + '.groovy'].

Post a Comment