The previous chapters have been related to developing Grails applications. One of the strengths of Grails is that it comes bundled with everything you need to begin developing and testing your application. Grails embeds a web container (Jetty) and a relational database (HSQLDB). All you have to do is execute the Grails run-app
target, and you have your entire runtime environment. However, at some point in time, you will want to expose your application to your users. The embedded runtime environment is for development and testing only, and it is not intended to scale or support the load necessary in a production environment.
This chapter focuses on deploying Grails applications to Java EE application servers and more robust database servers. It also covers some other miscellaneous, operational aspects, such as upgrading a Grails application when a new version of the Grails framework is released and automating tasks using Gant.
Deploying a Grails application involves three steps. First, you need to configure the application. This typically involves environment-specific configurations. Second, you package the application. For Grails applications, this means bundling all the code and related artifacts into a WAR file. The final step is to actually deploy the application to an application server or web container.
Many organizations have multiple environments or gates that an application must pass through before reaching production and users. At a minimum, each application should have to pass through development, test, and production environments. The development environment is the developer's machine. In the test environment, which mimics production, somebody other than the developer completes quality assurance by validating that the application meets requirements and generally works. The production environment is where real users use the application. In each of these environments, you're likely to have environment-specific configurations and, rarer, behavioral differences. For example, in development, you may want to point to a local HSQLDB in-memory database, but in the test and production environments, you may need to point at a remote server database such as MySQL.1
As you might expect, Grails follows these best practices and is aware of these three environments. You can use these environments when calling the grails
command line as the second parameter or in configuration files such as DataSource.groovy
and Config.groovy
, which you'll see in the next section. Table 12-1 shows the mapping per environment.
Table 12-1. Environment Mappings
Environment | Command Line | Configuration File Reference |
Development | dev |
development |
Test | test |
test |
Production | prod |
production |
Depending on the size of the organization and the criticalness of the application or the system, you may have additional environments such as integration testing (IT), user acceptance testing (UAT), and performance testing (PT). You can use custom environments as well. The only requirement is that the grails.env
system property must be passed to the grails
command line. For example, the following would specify the performance environment:
> grails -Dgrails.env=PT run-app
Grails contains four primary configuration categories. The first is URL mapping, which we explained and demonstrated thoroughly in Chapter 9, so we won't be revisiting it here. The second is behavior when the application starts up and shuts down. The third and fourth are data source and logging configurations. You can find all these configurations in the grails-app/config
directory.
Startup and Shutdown Behavior
Sometimes when an application starts up and/or shuts down, you need to do things such as acquire and release resources, respectively, or cache data. Grails makes this possible in the grails-app/config/BootStrap.groovy
file, which you first saw in Chapter 7. Listing 12-1 is an example of a BootStrap.groovy
file. It includes comments where startup and shutdown code would go.
__________
Listing 12-1. Using BootStrap.groovy to Perform Startup and Shutdown Activities
class BootStrap {
def init = { servletContext ->
// perform startup activities here
}
def destroy = {
// perform shutdown activities here
}
}
The init
action is invoked when the application starts up or is redeployed. The javax.servlet.ServletContext
2 is passed in, providing access to the application attributes, initialization parameters configured in web.xml
, the context path, and more. The destroy
action is invoked when the application is shut down, but it is not guaranteed to be called. For example, it is not likely the destroy
method will be called when the application server is shut down, but it is likely to be called when the application is redeployed or undeployed.
Note As discussed and demonstrated in Chapter 7's "Bootstrapping" sidebar, you can use the GrailsUtil.environment()
to determine which environment the application is running in and perform the appropriate bootstrapping code.
Data Source Configurations
By default, Grails is configured out of the box to use an embedded, in-memory HSQLDB database. This is not likely to be the database used in the test and production environments and possibly not even in most development environments, because as you've seen, each time the application restarts, the database gets re-created in memory and is therefore empty. It's more likely that an application will use a server database such as MySQL, Oracle,3 DB2,4 Microsoft SQL Server,5 or maybe even Apache Derby.6 It might even use HSQLDB in a file mode. Any Hibernate-supported database7 should be able to be used.
__________
You can set database and Hibernate configurations in the grails-app/config/Data Source.groovy
file. Listing 12-2 shows an example of a DataSource.groovy
file that has been customized to include a production database configuration for a local MySQL database.
Note You can find installation and configuration instructions for MySQL at http://www.beginninggroovyandgrails.com
.
Listing 12-2. DataSource.groovy Containing a MySQL Production Configuration
01 dataSource {
02 pooled = false
03 driverClassName = "org.hsqldb.jdbcDriver"
04 username = "sa"
05 password = ""
06 }
07 hibernate {
08 cache.use_second_level_cache=true
09 cache.use_query_cache=true
10 cache.provider_class='org.hibernate.cache.EhCacheProvider'
11 }
12 // environment specific settings
13 environments {
14 development {
15 dataSource {
16 dbCreate = "create-drop" // one of 'create', 'create-drop','update'
17 url = "jdbc:hsqldb:mem:devDB"
18 }
19 }
20 test {
21 dataSource {
22 dbCreate = "update"
23 url = "jdbc:hsqldb:mem:testDb"
24 }
25 }
26 production {
27 dataSource {
28 pooled = true
29 driverClassName = "com.mysql.jdbc.Driver"
30 username = "root"
31 password = "<password>"
32 dbCreate = "update"
33 url = "jdbc:mysql://localhost:3306/collab_todo"
34 }
35 }
36 }
_________
The configuration file in Listing 12-2 is separated into three main parts: dataSource
(lines 1–6), hibernate
(lines 7–11), and environment-specific settings (lines 12–36). The dataSource
section provides default database settings that environment-specific settings may override or append to. Other than the pooled
property, these default settings all relate to standard JDBC configuration information, such as the JDBC driver class name, the username, and the password for the database.
The hibernate
section relates to Hibernate-specific settings. By default, it configures Hibernate caching settings. See the Hibernate documentation8 for more configuration options.
Finally, the environment-specific settings can provide specific data source or Hibernate configurations for a particular named environment. Notice in lines 28–33 that the production dataSource
is configured to use a MySQL database by setting the driverClassName
and url
to be MySQL-specific. It also overrides the pooled
property by setting it to true
, since most production environments have more concurrent needs than a developer's workstation. Finally, note that the dbCreate
property is configured only for update
. This means that at deployment time, Hibernate will update any of the tables it is able to, but it will leave the existing data intact. On the other hand, the default development configuration will create the table at startup and destroy the tables and data when the application is shut down.
The DataSource.groovy
configuration file is not the only application configuration that you must complete to support connection to the database. You also must include the database driver JAR in the classpath of the application. The easiest way to do this is to simply copy the JAR(s) to the project lib
directory. At deployment or packaging time, Grails will copy the JAR file to the WEB-INF/lib
directory. For a MySQL database, you would need to copy the mysql-connector-java-X.X.X-bin.jar
file to the lib
directory.
__________
Logging is an important part of gathering feedback about the state of an application. As you learned in Chapter 5, Grails provides logging support using the Apache Commons Logging component9 and Apache log4j.10 You can make the log4j configurations, as well as a couple other configurations, in grails-app/config/Config.groovy
. Listing 12-3 shows the default version of Config.groovy
.
Listing 12-3. Config.groovy File Containing Logging Configurations
01 // log4j configuration
02 log4j {
03 appender.stdout = "org.apache.log4j.ConsoleAppender"
04 appender.'stdout.layout'="org.apache.log4j.PatternLayout"
05 appender.'stdout.layout.ConversionPattern'='[%r] %c{2} %m%n'
06 rootLogger="error,stdout"
07 logger {
08 grails="info,stdout"
09 org {
10 codehaus.groovy.grails.web.servlet="off,stdout" // controllers
11 codehaus.groovy.grails.web.pages="off,stdout" // GSP
12 codehaus.groovy.grails.web.sitemesh="off,stdout" // layouts
13 codehaus.groovy.grails."web.mapping.filter"="off,stdout" // URL mapping
14 codehaus.groovy.grails."web.mapping"="off,stdout" // URL mapping
15 codehaus.groovy.grails.commons="off,stdout" // core / classloading
16 codehaus.groovy.grails.plugins="off,stdout" // plugins
17 codehaus.groovy.grails.orm.hibernate="info,stdout" // hibernate integration
18 springframework="off,stdout"
19 hibernate="off,stdout"
20 }
21 }
22 additivity.'default' = false
23 additivity {
24 grails=false
25 org {
26 codehaus.groovy.grails=false
27 springframework=false
28 hibernate=false
29 }
30 }
31 }
32
33 // The following properties have been added by the Upgrade process...
34 grails.views.default.codec="none" // none, html, base64
35 grails.views.gsp.encoding="UTF-8"
__________
In Listing 12-3, lines 2–31 configure log4j, while the remaining lines set some default configurations for views. When the application logs a message, something has to be done with the message. Lines 3–5 configure a ConsoleAppender
, which takes the message and writes it to standard out with the format defined by the pattern in line 5. Line 6 instructs log4j to send only messages with severities of error
or greater to the appender unless explicitly overwritten. Lines 7–20 show examples of overriding some logging. For example, on line 8, the grails
logger says to include anything with a log level of info
or above, while line 10 turns off org.codehaus.groovy.grails.web.servlet
completely.
Note There are a lot of configuration options for log4j. Check out the "Short introduction to log4j"11 for more details.
Grails provides some special loggers for the different types of artifacts that it already understands by conventions. Table 12-2 documents the special loggers you will find helpful for seeing your log messages.
Table 12-2. Special Grails Artifact Loggers
Logger | Description |
grails.app.controller |
Configures logging for all your controllers |
grails.app.domain |
Configures logging for all your domains |
grails.app.service |
Configures logging for all your services |
grails.app.tagLib |
Configures logging for all your tag libraries |
The most likely log configuration you will want to make is adding environment-specific logging for your artifacts; you can use the loggers described in Table 12-2. For example, in your development environment, you may want to log messages at a debug level (as shown in Listing 12-4), but in your production environment, you may want to log fewer messages for performance reasons and to ensure that the log file doesn't consume all your disk space.
__________
Listing 12-4. Example of Adding Logging Specific to Your Development Environment
environments {
development {
log4j {
logger {
grails {
app.controller="debug"
}
}
}
}
}
Listing 12-4 shows an example of logging all controllers at a debug level. You can simply add this configuration to the end of the Config.groovy
file and then restart the application for the new development-specific logging configuration to take effect.
After you complete the application functionality for an iteration or a release, you or your build master will have to package your application so it can be deployed on a machine other than your computer. At the most basic level, all you have to do is run the Grails war
target to create a deployable WAR file. In reality, though, you should follow a more disciplined process to make it easier to identify the version of your application as it goes through environments. We recommended you follow this procedure for milestone releases:
app.version
property in application.properties
either manually or by using the grails set-version
target to identify a milestone release number, such as X.X.X
.grails clean
target to make sure there are no leftover artifacts.grails war
target and an environment designation—for example, grails prod war
. This creates a WAR file in the root of the project with a name containing the project name and version number.app.version
property and append a -SNAPSHOT
in application
.properties
either manually or by using the grails set-version
target to indicate this version is a work in progress and not a milestone release.application.properties
file back into your version control repository.Now you have a WAR file ready for deployment. We'll discuss how to deploy it in the next section.
A Grails application packaged as a WAR file can be deployed to Java EE application servers such as JBoss,12 GlassFish,13 ApacheGeronimo,14 BEA WebLogic,15 or IBM WebSphere,16 or to a web container such as Apache Tomcat17 or Jetty.18 Deployment between containers varies greatly, so consult your application server or web container documentation for details. However, standard mechanisms include special deployment directories where the WAR can be copied, a web-based administrator console, a command-line client, and/or Apache Ant tasks. Grails does not provide anything for simplifying deployments, so the next section explains how you can write your own script to automate the process.
Note The Grails FAQ19 has specific configurations and tips for deploying Grails applications to some common application servers.
__________
Development is full of cycles and repetitive tasks, such as compiling, packaging, and deploying. Performing such tasks manually can be boring and error prone. It is considered a best practice to automate such tasks. Many books have been written to this effect, and many frameworks have been developed to solve the problem. In fact, one of the primary conventions for Grails is the grails
command line, which is used to automate common tasks in Grails development. The Grails command line utilizes Gant,20 a build system that uses the Groovy language to script Apache Ant21 tasks rather than Ant's XML format. Ant, and therefore Gant, are primarily made up of name collections of tasks referred to as targets, which you can execute to complete a unit of work.
Note Neal Ford,22 author and frequent speaker on the "No Fluff Just Stuff" symposium series,23 describes the importance of automation as, "Doing work like a manual laborer makes you dumber, figuring out how to automate it makes you smarter so be a craftsman not a laborer."
As you have seen throughout this book, the Grails command line provides a lot of functionality. However, it may not automate every task you perform during your development. For example, there is no task for deploying, and yet it is common to deploy your application to infrastructure that matches the application server and database you use in a production environment. So from time to time, you may want to simplify your development efforts by creating your own Gant scripts or modifying existing ones.
Grails makes it easy to incorporate your scripts into your development process. After all, every Grails command-line task is itself a Gant script already. The Grails command line uses the following directories to locate scripts for execution and incorporate them into the help system:
USER_HOME/.grails/scripts
PROJECT_HOME/scripts
PROJECT_HOME/plugins/*/scripts
GRAILS_HOME/scripts
__________
After writing your Gant script, you can place it in one of these directories, and it will automatically be available from the Grails command line and in the Grails help list.
Grails does not include a deployment script, because there are too many application servers and configuration options to keep up. Listing 12-5 shows an example of a simple script you can use to deploy a WAR file to an application server that supports automatic deployments via a deployment directory like JBoss has.
Note You can find installation and configuration instructions for JBoss at http://www.beginninggroovyandgrails.com
.
Listing 12-5. Basic Deployment Script Deploy.groovy
01 /**
02 * Gant script that copies a WAR file to an application
03 * server deployment directory.
04 */
05
06 Ant.property(environment:"env")
07 grailsHome = Ant.antProject.properties."env.GRAILS_HOME"
08
09 includeTargets << new File ( "${grailsHome}/scripts/War.groovy" )
10
11 target ('default':'''Copies a WAR archive to a Java EE app server's deploy
12 directory.
13
14 Example:
15 grails deploy
16 grails prod deploy
17 ''') {
18 deploy()
19 }
20
21 target (deploy: "The implementation target") {
22 depends( war )
23
24 def deployDir = Ant.antProject.properties.'deploy.dir'
25
26 Ant.copy(todir:"${deployDir}", overwrite:true) {
27 fileset(dir:"${basedir}", includes:"*.war")
28 }
29
30 event("StatusFinal", ["Done copying WAR to ${deployDir}"])
31 }
The Deploy.groovy
script shown in Listing 12-5 begins by loading all system environment variables and then storing the GRAILS_HOME
environment variable into a local variable on lines 6 and 7. Line 9 imports another Gant script—specifically, the War.groovy
script. The deploy script is dependent on the War.groovy
script to build the WAR file, so it has something to deploy.
Lines 11–19 represent the first of two targets in this script. The first target is the default
target, which means if no other target is specified, this will be the one executed. Since Grails calls the default
target, it will definitely be the one executed. Notice that the default
name is in single quotes; this is because the word default
is a reserved word in Groovy. Quotes are not normally needed for target names. Following the name is the target description, which the Grails help system uses. The only behavior the default target has is to call the deploy
target.
The deploy
target, shown on lines 21–31, does all the real work. It begins by calling the war
target from the War.groovy
script. After the WAR file has been created, it looks up the deploy.dir
property. It then copies the WAR file to the location of this property. You can put the destination of the WAR file in the application.properties
file, since the Grails command line loads it automatically. Lines 26–28 use the Ant copy
task to copy all WAR files to the deployment directory. Finally, a message is printed to the system out to indicate to the user that the script is complete and which directory the WAR file has been copied to.
Running the following target performs the deployment by copying the WAR file to your application server:
> grails deploy
Note If you need to deploy to a remote application server, you might be able to use Apache Ant's Secure Copy Protocol (SCP) task to copy a WAR to a remote server running Secure Shell (SSH).
Early in the development of the Grails framework, it must have become obvious that the framework would go through many iterations and that some mechanism was needed to ensure that applications could migrate easily to new releases of the Grails framework. As with many of the Grails conventions, this is accomplished through a Grails target, upgrade
.
During the startup of an application using the run-app
target, Grails checks the application metadata found in the application.properties
file (see Listing 12-6) located in the root of the project directory structure for the app.grails.version
number.
Listing 12-6. The application.properties File
#Do not edit app.grails.* properties, they may change automatically.
#DO NOT put application configuration in here, it is not the right place!
#Fri Dec 28 22:26:01 EST 2007
app.version=0.1
app.servlet.version=2.4
app.grails.version=1.0
app.name=collab-todo
If the currently configured version of Grails doesn't match the application metadata's app.grails.version
number, Grails will display the following message:
Application expects grails version [1.0], but GRAILS_HOME is version [1.0.2] –
use the correct Grails version or run 'grails upgrade' if this Grails version is
newer than the version your application expects.
Upgrading the application is as easy as running grails upgrade
.
Caution When upgrading, Grails may overwrite existing files. It's a good idea to ensure your application is in sync with your version control repository before running the upgrade
target.
This chapter covered a lot of the operational aspects of developing Grails applications. Many of the topics related to things that happen after the code is written or to helping facilitate the development process. The topics included packaging and deploying the application as well as configuring environmental data sources and logging. It also covered how to automate your daily development processes and upgrade your applications to work with new versions of Grails. This chapter also ends the server-side discussion of Grails. The remaining chapter discusses aspects of writing clients that may utilize the deployed application.