Loading...

Friday, February 4, 2011

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

If we work on a Grails project and we want to deploy our application as Web Application Archive (WAR) it is easy to create the file. To create a WAR file of our Grails application we simply invoke the command: $ grails war. Suppose we want to put our WAR file first on a system test application server, then a user acceptance test application server and finally the production server. We want this WAR file to be self contained and all code and configuration must be in the WAR file. We don't want to generate a WAR file for each environment separately, but a single WAR must be passed through the different environments. In this post we see how we can do this.

Suppose we have a Grails application and we define a systemTest and userAcceptanceTest environment next to the default development, test and production environments. We add these new environments to the environments block in grails-app/conf/Config.groovy and set a simple property runningMode with a different value for each environment.

// File: grails-app/conf/Config.groovy

...

environments {
    production {
        runningMode = 'LIVE'
    }
    development {
        runningMode = 'DEV'
    }
    test {
        runningMode = 'INTEGRATION TEST'
    }
    systemTest {
        runningMode = 'SYSTEM TEST'
    }
    userAcceptanceTest {
        runningMode = 'USER ACCEPTANCE TEST'
    }
}

...

Next we are going to change our grails-app/views/index.gsp and add a little code to show the value of the property runningMode. This way we can show which environment is used by the running WAR.

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

...

<h1>Application Status</h1>
<ul>
    <li>Running mode: ${grailsApplication.config.runningMode}</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>

...

Let's package the application in a WAR file:

$ grails war

Next we can deploy the WAR file to our application servers. But how can we set the environment for our application, so we can see the right value of our configuration property runningMode? Answer: We need to set the system property grails.env with the correct value before we start the application server. The Grails application determines in which environment the application is running by looking at the system property grails.env.

Suppose we use Tomcat as our servlet container for the Grails application. We defined separate Tomcat instances for each environment (system test, user acceptance test and production). Before we start an instance we can use the environment variable CATALINA_OPTS to set the system property grails.env. For example for the system test Tomcat intance we define CATALINA_OPTS as:

$ export CATALINA_OPTS=-Dgrails.env=systemTest

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 runningMode:

And we see the different values for the different servers. So it is very easy to create a single WAR file, but with different configuration settings for different environments, because of the environments support in Grails. We only have to tell the application server via system property grails.env which environment settings need to be used.

In the following post we learn how we can use configuration files outside of the application code. Per environment we can set a configuration property in separate files.

5 comments:

Erik Pragt said...

Ow, it's terrible to see that people still want to pack their configuration inside a war...

Erik Pragt said...

Ah, and luckily there's a part II. Much better!

Anonymous said...

So 'grails dev war', 'grails test war', 'grails prod war' are all the same but with different grails.env set as default?
Does the dev war file have still the prod configuration in it?
I always though the other environment settings are erased and I couldn't run a dev war with prod settings even with grails.env setting set.

Hubert Klein Ikkink said...

@Anonymous: the settings are not erased and can be enabled using the -Dgrails.env system property.

Carlos said...

AWESOME! Thanks!

Post a Comment