Loading...

Friday, February 25, 2011

Grails Goodness: Controller Properties as Model

To pass data from a controller to a view we must return a model. The model is a map with all the values we want to show on the Groovy Server Page (GSP). We can explicitly return a model from an action, but if we don't do that the controller's properties are passed as the model to the view. Remember that in Grails a new controller instance is created for each request. So it is save to use the properties of the controller as model in our views.

// File: grails-app/controllers/com/mrhaki/SampleController.groovy
package com.mrhaki

class SampleController {

    def values = ['Grails', 'Groovy', 'Griffon', 'Gradle', 'Spock']

    def greeting

    def index = {
        greeting = 'Welcome to My Blog'
        // Don't return a model, so the properties become the model.
    }
}
<%-- File: grails-app/views/sample/index.gsp --%>
<html>
    <head>
    </head>
    <body>
        <h1>${greeting}</h1>

        <g:join in="${values}"/> rock!
    </body>
</html>

Thursday, February 24, 2011

Grails Goodness: Set Application Wide Default Layout

Grails uses Sitemesh as the layout and decoration framework. Layouts are defined in the grails-app/views/layouts directory. There are several conventions Grails uses to determine which layout file must be applied. We can set a default layout for our application by setting the property grails.sitemesh.default.layout in grails-app/conf/Config.groovy. The value of the property maps to the filename of the layout. For example if we set the value to main then Grails will use grails-app/views/layouts/main.gsp.

Another way is to create a layout with the name application.gsp and save it in grails-app/views/layouts. Grails will use this layout if the layout cannot be determined in another way.

Wednesday, February 23, 2011

Grails Goodness: Profile Script Tasks

If we want to know how long the execution of a Grails task takes we can enable profiling. If we enable profiling we can see for example how long it takes to compile the source code. We can enable the profiling information by setting the system property grails.script.profile with the value true.

$ grails -Dgrails.script.profile=true compile

Another way to enable profiling of the Grails tasks is to set the property grails.script.file with the value true in grails-app/conf/BuildConfig.groovy.

// File: grails-app/conf/BuildConfig.groovy
...
grails.script.profile=true
...

If we run a Grails script and profiling is enabled we see the information in the console output:

$ grails -Dgrails.script.profile=true compile
Welcome to Grails 1.3.7 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: /opt/local/grails/current

Base Directory: /Users/mrhaki/Projects/sample
Resolving dependencies...
Dependencies resolved in 3113ms.
Running script /opt/local/grails/current/scripts/Compile.groovy
Environment set to development
Profiling [Compiling sources to location [/Users/mrhaki/.grails/1.3.7/projects/sample/plugin-classes]] start
Profiling [Compiling sources to location [/Users/mrhaki/.grails/1.3.7/projects/sample/plugin-classes]] finish. Took 2319 ms
Profiling [Compiling sources to location [target/classes]] start
Profiling [Compiling sources to location [target/classes]] finish. Took 317 ms

Tuesday, February 22, 2011

Grails Goodness: Encode Content with the encodeAs Tag

Encoding and decoding values is easy in Grails. We can invoke the dynamic methods encodeAs...() and decodeAs...() for several codecs. If we have a large block of content on our Groovy Server Page (GSP) we want to encode we can use the <g:encodeAs codec="..."/> tag. The body of the tag is encoded with the codec we specify with the codec attribute.

<%-- Sample.gsp --%>

<h1>Sample Title</h1>

<g:encodeAs codec="HTML">
<h1>Sample Title</h1>
</g:encodeAs>    

If we look at the generated HTML source we see:

<h1>Sample Title</h1>

&lt;h1&gt;Sample Title&lt;/h1&gt;

Monday, February 21, 2011

Grails Goodness: Format Boolean Values with the formatBoolean Tag

If we want to display something else than true or false for a boolean value on our Groovy Server Page (GSP) we can use the formatBoolean tag. We can specify a value for true with the true attribute and for false with the false attribute. If we don't specify a true or false attribute Grails will look for the key boolean.true and boolean.false in the i18n resource bundle. If those are not found than the keys default.boolean.true and default.boolean.false are used. And the last fallback are the values True for true and False for false boolean values.

// File: grails-app/i18n/messages.properties
boolean.true=Okay
boolean.false=Not okay
<%-- Sample.gsp --%>

<g:formatBoolean boolean="${true}"/> outputs: Okay
<g:formatBoolean boolean="${false}"/> outputs: Not okay

<g:formatBoolean boolean="${true}" true="Yes" false="No"/> outputs: Yes
<g:formatBoolean boolean="${false}" true="Yes" false="No"/> outputs: No

Sunday, February 20, 2011

Grails Goodness: The Link Namespace

Grails supports named URL mappings. We can define a name for a URL mapping and use that name when we generate links in our application. In this post we see how we can use the link namespace to use a named mapping.

We start with a simple named URL mapping for viewing product details on our site:

// File: grails-app/conf/UrlMappings.groovy
...
name productDetails: "/product/details/$ref" {
    controller: 'product'
    action: 'details'
}
...

We can use the <g:link mapping="..." .../> tag in our code to use this named URL mapping:

<%-- Sample GSP --%>

<g:link mapping="productDetails" params="[ref: product.identifier]" class="nav">Details</g:link> 
outputs for product with identifier '901':
<a href="/context/product/details/901" class="nav">Details</a>

But we can also use the special link namespace in our code. We start a new tag with link as namespace. The name of the tag is the name of the URL mapping we have created. The attributes we specify are all converted to parameters for the link. If we add the attrs attribute we can specify attribute key/value pairs that need to be applied to the generated link as is.

<%-- Sample GSP --%>

<link:productDetails ref="${product.identifier}" attrs="[class: 'nav']">Details</link:productDetails> 
outputs for product with identifier '901':
<a href="/context/product/details/901" class="nav">Details</a>

Saturday, February 19, 2011

Grails Goodness: Templates Can Have a Body

To create a more modular Groovy Server Page we can use Grails' template support. We use <g:render template="..." ... /> or <tmpl:templateName ... /> tags to render the template content. These tags can have a body. The body of the tag is then available in the template code. We use the expression ${body()} in our template to output the body content.

Suppose we have the following template code:

<%-- File: grails-app/views/product/_productView.gsp --%>
<h2>${product.name}</h2>

${body()}

We can use the template with different body contents:

...
<g:each in="${products}" var="product">
    <g:render template="productView" model="[product: product]">
        <g:link uri="/">Back to home</g:link>
    </g:render>
</g:each>
...
<g:each in="${products}" var="product">
    <tmpl:productView product="${product}">
        <g:link controller="product" action="details" id="${product.id}">More details</g:link>
    </tmpl:productView>
</g:each>
...

Grails Goodness: The Template Namespace

To have clean and re-usable Groovy Server Pages (GSP) we can use templates on our pages. A template contains HTML and code that we can maintain separately. In this post we learn about the template namespace to include a template on our page.

Suppose we have a page in our application that display a list of products. Each product has several properties we show. The template for a product is:

<%-- File: grails-app/views/product/_productView.gsp --%>
<li class="${cssClassName}">
    ${product.identifier}
    ${product.name}
    <g:formatNumber number="${product.price}" type="currency" currencyCode="EUR"/>
</li>

We can use the template with the g:render tag and template attribute on our page:

<%-- File: grails-app/views/product/list.gsp --%>
...
<ul>
    <g:render template="productView" 
              var="product" collection="${products}" 
              model="[cssClassName: 'info']"/>
</ul>
...
<ul>
    <g:each in="${products}" var="product">
        <g:render template="productView" model="[product: product, cssClassName: 'info']"/>
    </g:each>
</ul>
...

But we can also use the template namespace feature in Grails. We define a tag with the namespace tmpl and the tagname is our template name. We pass the model for the template through the attributes. Each attribute name/value pair is passed as model to the template.

<%-- File: grails-app/views/product/list.gsp --%>
...
<ul>
    <g:each in="${products}" var="product">
        <tmpl:productView product="${product}" cssClassName="info"/>
    </g:each>
</ul>
...

Grails Goodness: Add More Paths to the Stats Report

If we invoke $ grails stats for our Grails project we get to see the number of files and lines of code (LOC) for several Grails artifacts. For example we can see how many controllers, services and taglibs are in our project and how many lines of code is written for each.

    +----------------------+-------+-------+
    | Name                 | Files |  LOC  |
    +----------------------+-------+-------+
    | Controllers          |     1 |    89 | 
    | Domain Classes       |     1 |     5 | 
    | Jobs                 |     1 |     6 | 
    | Unit Tests           |     3 |    36 | 
    | Scripts              |     1 |     4 | 
    +----------------------+-------+-------+
    | Totals               |     7 |   140 | 
    +----------------------+-------+-------+

We can add new source directories to the report. When the stats report is generated the StatsStart event is triggered. The default list of paths is passed as the argument of the event. We can subscribe to this event in our own Grails application. Because we get the list of paths as an argument, we can define our own path info and add it to the list. We add the paths grails-app/conf and grails-app/utils to be included in the stats report.

// File: scripts/_Events.groovy
eventStatsStart = { pathInfo ->
    def confPathInfo = [name: "Configuration Files", path: "^grails-app.conf", filetype: [".groovy"]]
    def utilPathInfo = [name: "Utils", path: "^grails-app.utils", filetype: [".groovy"]]
    pathInfo << confPathInfo << utilPathInfo
}

Now we can run the stats command again and we see the new paths in our report:

    +----------------------+-------+-------+
    | Name                 | Files |  LOC  |
    +----------------------+-------+-------+
    | Controllers          |     1 |    89 | 
    | Domain Classes       |     1 |     5 | 
    | Jobs                 |     1 |     6 | 
    | Unit Tests           |     3 |    36 | 
    | Scripts              |     1 |     5 | 
    | Configuration Files  |     7 |    87 | 
    | Utils                |     1 |     5 | 
    +----------------------+-------+-------+
    | Totals               |    15 |   233 | 
    +----------------------+-------+-------+

Friday, February 18, 2011

Grails Goodness: Define Date Format in i18n ResourceBundle

The Grails formatDate tag supports the formatName attribute. The value of this property is the lookup key for the date format defined in the i18n properties files. So we can define a custom date format in grails-app/i18n/messages.properties and use it with the formatDate tag.

If we don't specify a value for the format and formatName attributes Grails will look for the keys date.format or default.date.format for a date format. If those keys cannot be found then the default pattern yyyy-MM-dd HH:mm:ss z' is used.

# File: grails-app/i18n/messages.properties
default.date.format=d/M/yyyy
custom.date.format=dd-MMM-yyyy
<%-- File: sample.gsp --%>

<g:set var="date" value="${new Date(111, 2, 21)}"/>

<g:formatDate date="${date}"/> outputs: 21/3/2011
<g:formatDate date="${date}" formatName="custom.date.format"/> outputs: 21-Mar-2011
<g:formatDate date="${date}" format="yyyy-MM-dd"/> outputs: 2011-03-21

Thursday, February 17, 2011

Grails Goodness: Use TimeAndSizeRollingAppender for Logging

In a previous post we learned how to use the Log4j Extras Companion RollingFileAppender. In this post we learn how to use TimeAndSizeRollingAppender. This appender has a lot of nice features among rolling over the log file at a time interval and we can limit the number of rolled over log files. With this combination we can keep a history of log files, but limit how many log files are saved.

First we must download the JAR file with the appender and save it in the lib directory of our Grails application. Next we can configure the appender in grails-app/conf/Conf.groovy:

// File: grails-app/conf/Config.groovy
import org.apache.log4j.appender.TimeAndSizeRollingAppender
...
log4j = {
    appenders {
        appender new TimeAndSizeRollingAppender(name: 'timeAndSizeRollingAppender',
                     file: 'logs/app.log', datePattern: '.yyyy-MM-dd',
                     maxRollFileCount: 7, compressionAlgorithm: 'GZ',
                     compressionMinQueueSize: 2,
                     layout: pattern(conversionPattern: "%d [%t] %-5p %c{2} %x - %m%n"))
    }

    root {
        // Use the appender.
        debug 'timeAndSizeRollingAppender'
    }
}
...

We configured the appender to rollover daily, compress the contents of the archived log files after 2 rollovers, and only save 7 archived log files.

Grails Goodness: Use Log4j Extras Companion RollingFileAppender

Apache Extras Companion for Log4j contains a RollingFileAppender, which can be configured to automatically compress old log files. We can even save the old, archived log files to another directory than the active log file. In this post we learn how we can add and configure the RollingFileAppender in our Grails application.

First we must define our dependency on the Log4j Extras Companion libary. We open grails-app/conf/BuildConfig.groovy and add to the dependencies section the following code:

// File: grails-app/conf/BuildConfig.groovy
...
grails.project.dependency.resolution = {
...
    dependencies {
        compile 'log4j:apache-log4j-extras:1.0'
    }
}
...

Next we can configure the appender in grails-app/conf/Config.groovy:

// File: grails-app/conf/Config.groovy
import org.apache.log4j.rolling.RollingFileAppender
import org.apache.log4j.rolling.TimeBasedRollingPolicy

...
log4j = {
    def rollingFile = new RollingFileAppender(name: 'rollingFileAppender', layout: pattern(conversionPattern: "%d [%t] %-5p %c{2} %x - %m%n"))
    // Rolling policy where log filename is logs/app.log.
    // Rollover each day, compress and save in logs/backup directory.
    def rollingPolicy = new TimeBasedRollingPolicy(fileNamePattern: 'logs/backup/app.%d{yyyy-MM-dd}.gz', activeFileName: 'logs/app.log')
    rollingPolicy.activateOptions()
    rollingFile.setRollingPolicy rollingPolicy

    appenders {
        appender rollingFile
    }

    root {
        // Use our newly created appender.
        debug 'rollingFileAppender'
    }
}
...

We use TimeBasedRollingPolicy, which is quite powerful. We can configure the rollover period using a date/time pattern. If the fileNamePattern ends with .gz the contents of the log file is compressed. Finally we decouple the active log file name from the location where the archived log files are saved with the property activeFileName.

Wednesday, February 9, 2011

Configure Log4j on Tomcat

How-to configure Log4j on Tomcat is described in the Tomcat documentation, but the documentation sample configuration is not correct. So in this post we see what we need to do to replace the default Java Util Logging (JUL) configuration and use Log4j in Tomcat. A big advantage is that if an application uses Log4j then we can configure the logging at a central place for the Tomcat instance. And another advantage is we can use our knowledge on how to configure Log4j logging and we don't have to learn Tomcat's syntax extensions to the JUL logging configuration.

Setup the classpath

First we must add same extra JAR files to our Tomcat classpath. We replace the default JUL Tomcat library with one that support Log4j. And of course we must add the Log4j library to the classpath.

Tomcat already provides the JAR files we need to use Log4j in Tomcat. These files are not in the normal distribution of Tomcat, but we can download them from the website. On the download page we must select the Browse link. From there we go to bin/extras and here we see two files we must download: tomcat-juli.jar and tomcat-juli-adapters.jar. We place the tomcat-juli.jar file in our $CATALINA_BASE/bin directory. The file tomcat-juli-adapters.jar is copied to our $CATALINA_BASE/lib directory.

Next we download the latest log4j 1.2 library from the download page. We must unpack the downloaded file to a directory on our computer. Next we copy from the directory with the extracted file we downloaded the file log4j-1.2.<version>.jar to the $CATALIN_BASE/lib directory.

Add Log4j configuration

Our classpath is now setup and we can add our Log4j configuration file. First we disable the old Tomcat JUL logging configuration. We find this configuration file is in the $CATALINA_BASE/conf directory. The name of the file is logging.properties and we move this file to $CATALINA_BASE/conf/logging.properties.jul. Tomcat cannot use the file for configuration, but we still have a backup. With the old configuration out of the way we can create a new Log4j configuration file. In the $CATALINA_BASE/lib directory we create the file log4j.properties. If we look at the sample configuration file in the Tomcat documentation we notice the file contains errors. For example the conversionPattern is not configured on the layout property. We can use the following sample Log4j configuration:

log4j.debug=true
log4j.rootLogger=INFO, CATALINA, CONSOLE

# Define all the appenders
log4j.appender.CATALINA=org.apache.log4j.FileAppender
log4j.appender.CATALINA.file=${catalina.base}/logs/catalina.log
log4j.appender.CATALINA.encoding=UTF-8
log4j.appender.CATALINA.layout=org.apache.log4j.PatternLayout
log4j.appender.CATALINA.layout.conversionPattern = %d [%t] %-5p %c - %m%n
log4j.appender.CATALINA.append=true

log4j.appender.LOCALHOST=org.apache.log4j.FileAppender
log4j.appender.LOCALHOST.file=${catalina.base}/logs/localhost.log
log4j.appender.LOCALHOST.encoding=UTF-8
log4j.appender.LOCALHOST.layout=org.apache.log4j.PatternLayout
log4j.appender.LOCALHOST.layout.conversionPattern = %d [%t] %-5p %c - %m%n
log4j.appender.LOCALHOST.append=true

log4j.appender.MANAGER=org.apache.log4j.FileAppender
log4j.appender.MANAGER.file=${catalina.base}/logs/manager.log
log4j.appender.MANAGER.encoding=UTF-8
log4j.appender.MANAGER.layout=org.apache.log4j.PatternLayout
log4j.appender.MANAGER.layout.conversionPattern = %d [%t] %-5p %c - %m%n
log4j.appender.MANAGER.append=true

log4j.appender.HOST-MANAGER=org.apache.log4j.FileAppender
log4j.appender.HOST-MANAGER.file=${catalina.base}/logs/host-manager.log
log4j.appender.HOST-MANAGER.encoding=UTF-8
log4j.appender.HOST-MANAGER.layout=org.apache.log4j.PatternLayout
log4j.appender.HOST-MANAGER.layout.conversionPattern = %d [%t] %-5p %c - %m%n
log4j.appender.HOST-MANAGER.append=true

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.encoding=UTF-8
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.conversionPattern=%d [%t] %-5p %c - %m%n

# Configure which loggers log to which appenders
log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost]=INFO, LOCALHOST
log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager]=\
  INFO, MANAGER
log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager]=\
  INFO, HOST-MANAGER

We are ready and we can start Tomcat. Tomcat starts up and uses Log4j for logging messages.

Everything works fine, but if we don't want to the Log4j configuration in the $CATALINA_BASE/lib directory but in the $CATALINA_BASE/conf directory? We can move the log4j.properties file from the $CATALINA_BASE/lib directory to the $CATALINA_BASE/conf directory. Then we must use the system property -Dlog4j.configuration=file://$CATALINA_BASE/conf/log4j.properties when we start Tomcat. In Tomcat 6 and 7 we can use the environment variable LOGGING_CONFIG to set this value, because it is used by the Catalina scripts when we start Tomcat.

Friday, February 4, 2011

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

In part 1 we learned how we can define environment specific configuration in our application code. In part 2 we moved some of the configuration outside the application code and into external configuration files. The goal is to have a single WAR file that can be deployed to several environments and still contains configuration properties per environment. We use $ grails war to create the WAR file and if we deploy this WAR file to for example Tomcat we see the display name of our Grails application is set to /sample-production-0.1:

The name consists of our application name, environment used to create the WAR file (by default Grails uses production when creating a WAR file) and the application version. Grails automatically sets this value when we package the application as WAR file. It can be confusing to see the environment production in the display name, so we set the value of the display name to a another value.

We first get the template web.xml Grails uses and set the value of display-name to a new value.

$ grails install-templates

We open src/templates/war/web.xml and look for the display-name element. The value is /@grails.project.key@. Grails uses the ANT replace task when building the WAR file to replace @grails.project.key@ with application name, environment and application version. We want a custom value so we change the display-name:

...

<display-name>Sample Application :: @grails.app.name.version@</display-name>

...

We use the @...@ syntax, because we will use the ANT replace task, to add the application name and version to the generated web.xml. Next we create scripts/_Events.groovy and listen to the WebXmlStart event. Here we get a hold on the web.xml and use the ANT replace task to inject the application name and version.

// File: scripts/_Events.groovy
eventWebXmlStart = { webXmlFile ->
    ant.echo message: "Change display-name for web.xml"
    def tmpWebXmlFile = new File(projectWorkDir, webXmlFile)
    ant.replace(file: tmpWebXmlFile, token: "@grails.app.name.version@",
                value: "${grailsAppName}-${grailsAppVersion}")
}

We are ready to create the WAR file ($ grails war) and deploy it to our Tomcat instance. If we look at the display name we see our custom display name Sample Application:: sample-0.1:

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.

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.