CHAPTER 12

Integrating Grails

So far, you've explored a number of the core concepts that underpin Grails. From controllers to GORM and services, you should now have a pretty good understanding of what makes Grails tick. In this chapter, you'll learn how you can fit Grails into your existing ecosystem. We hope what you'll get from this chapter is a good understanding of how to go about including Grails into your build system, development tools, reporting setup, and server environment.

There is a lot of ground to cover, so let's get started by taking a closer look at configuration in Grails.

Grails and Configuration

Using Convention over Configuration (CoC), Grails significantly reduces the amount of configuration you need to do. Crucially, however, it is convention over configuration, not instead of it. There are still a number of different ways you can configure Grails.

Most configuration can be done using Grails' central configuration mechanism. The file grails-app/conf/Config.groovy contains any global configuration for the application. You've already seen this file being used at various points throughout the book. In the following sections, we'll be taking a closer look at how configuration is done with Config.groovy and what configuration options are available to you.

Configuration Basics

The Config.groovy file is a Groovy script that is similar to a regular Java properties file. You can set properties using the dot dereference operator:

grails.mime.file.extensions = true

Since it's a Groovy script, all the type information is retained. So, in the previous example, a boolean property called grails.mime.file.extensions is set to true. To access this setting, you can use the config property of the grailsApplication object available in controllers and views:

assert grailsApplication.config.grails.mime.file.extensions == true

As well as supporting settings specified on a single line, like the grails.mime.file. extensions setting, you can also group settings using blocks, as shown in Listing 12-1.

Listitng 12-1. Grouping Settings in Config.groovy

grails.mime {
    file.extensions = true
    types = [html: 'text/html']
}

The example in Listing 12-1 will produce two entries in config: grails.mime.file. extensions and grails.mime.types. You can also configure settings on a per-environment basis, which we'll cover in the next section.

Environment-Specific Configuration

As you discovered in Chapter 2, the grails-app/conf/DataSource.groovy file can be configured in an environment-specific way. This is because Grails uses the same mechanism to configure the DataSource as Config.groovy uses for the rest of the application.

Like with DataSource.groovy, by using Config.groovy you can specify environment-specific settings using the environments block, as shown in Listing 12-2.

Listitng 12-2. Environment-Specific Configuration

// set per-environment serverURL stem for creating absolute links
environments {
    development {
        grails.serverURL = "http://localhost:8080"
    }
    production {
        grails.serverURL = "http://www.gtunes.com"
    }
}

As Listing 12-2 demonstrates, you can use the environments block to specify a different grails.serverURL setting for production and development environments. The grails. serverURL setting is one of a number of built-in settings that you'll be discovering through the course of this book.

Configuring Logging

Grails uses the popular Log4j (http://logging.apache.org/log4j/) library to configure logging. Traditionally, Log4j has been configured with either a properties file format or XML. Grails, however, provides a specific DSL for configuring logging. Within the Config.groovy script, you can set a property called log4j using a Groovy closure.

Within this closure, you can use the Log4j DSL to configure logging. Listing 12-3 shows the default Log4j configuration in Grails that sets up logging for a bunch of packages internal to Grails.

Listitng 12-3. The Default Log4j Configuration

// log4j configuration
log4j = {
    error 'codehaus.groovy.grails.web.servlet', // controllers
             'codehaus.groovy.grails.web.pages', // GSP
             'codehaus.groovy.grails.web.sitemesh', // layouts
             'codehaus.groovy.grails.web.mapping.filter', // URL mapping
             'codehaus.groovy.grails.web.mapping', // URL Mapping
             'codehaus.groovy.grails.commons',// core / classloading
             'codehaus.groovy.grails.plugins',// plugins
             'codehaus.groovy.grails.orm.hibernate' // hibernate integration
}

As you can see from Listing 12-3, inside the body of the log4j closure there is an error method invoked that is passed a number of packages as arguments. The error method sets up the specified packages at the error debug level. The following debug levels are available going from least to most verbose:

  • off:No logging at all.
  • fatal:Log only fatal errors, which are typically errors that would cause an application to abort.
  • error:Log all errors that occur but still allow the application to continue running.
  • warn:Log scenarios that could be potentially harmful.
  • info:Log informational messages that describe the progress of the application.
  • debug:Log information that is used to debug an application.
  • trace:The trace level is for even finer-grained events than the debug level.
  • all:Log all messages that occur.

Sources within your own application can also be configured for logging. In Chapter 4 you learned about the log property available in every controller, tag library, or service. The output of this log property by default will use the root logging level of error. However, you can use the name of the class, starting with grails.app, to configure different logging behavior. For example, if you want to see output from all log statements in the UserController and AlbumArtService classes at the debug level, you could use the configuration in Listing 12-4.

Listitng 12-4. Setting the Debug Level

log4j {
    debug 'grails.app.controller.UserController',
                'grails.app.service.AlbumArtService'
}

Using sensible defaults, Grails will automatically configure a console appender that logs to standard out, while the root logger is set to the error level. You can also create your own custom Log4j appenders. For example, the code in Listing 12-5 sets up an additional file appender that writes the log to a file.

Listitng 12-5. Configuring a File Appender

log4j {
    appenders {
        rollingFile name:"myLog",
                        file:"/var/log/gtunes.log",
                        maxFileSize:"1MB",
                        layout: pattern(conversionPattern: '%c{2} %m%n')
    }
    ...
}

The example in Listing 12-5 uses a rollingFile appender, which is an org.apache. log4j.RollingFileAppender instance internally. Each named argument is a property of the org.apache.log4j.RollingFileAppender class, so to understand the configuration options, you just have to look at the Log4j APIs. The following is a list of the available Log4j appenders:

  • jdbc:The org.apache.log4j.jdbc.JDBCAppender logs to a database connection.
  • null:The org.apache.log4j.varia.NullAppender does nothing!
  • console:The org.apache.log4j.ConsoleAppender logs to standard out.
  • file:This is an org.apache.log4j.FileAppender that logs to a single file.
  • rollingFile: This is an org.apache.log4j.RollingFileAppender that logs to a file that gets automatically backed up and re-created when a maximum size is hit.

You can also use the Log4j API yourself to create an appender programmatically and then simply call the appender method, passing your appender, to add your own appender. Notice also that Listing 12-5 uses the pattern method to define the layout property of the appender. This translates into an org.apache.log4j.PatternLayout instance. You can use a number of other layout styles, including the following:

  • xml:An org.apache.log4j.xml.XMLLayout instance that outputs the log file in XML format.
  • html:An org.apache.log4j.HTMLLayout instance that outputs the logs in HTML.
  • simple:An org.apache.log4j.SimpleLayout instance that outputs to a preconfigured text format.
  • pattern:An org.apache.log4j.PatternLayout instance that allows you to configure the output from Log4j. See the javadoc API for details.

Once you have an appender, you have to tell Log4j which packages need to be logged to that appender. Listing 12-6 shows an example of logging Hibernate output to the rollingFile appender defined earlier at the trace level.

Listitng 12-6. Using an Appender

log4j {
    ...
    trace myLog:"org.hibernate"
    debug myLog:["org.codehaus.groovy.grails.web.mapping.filter",
                 "org.codehaus.groovy.grails.web.mapping"]}

Notice that you reference the appender by the name given to it using the name argument. Finally, there is one special logger for stack traces, which we'll discuss in the next section.

Stack Trace Filtering

Whenever an exception is thrown in Grails, the exception's stack trace will be filtered of all Groovy and Grails internals before it is logged. This is very useful because it allows you to narrow the problem down to how it relates to your code. Otherwise, you could be sifting through a rather large stack trace because all the internal layers of Grails are exposed.

Normally, when an exception is thrown in development, you can work out from the filtered trace what the problem is. On a rare occasion, you may want to inspect the full nonfiltered stack trace. Grails, by default, sets up a special logger to which it will log the full stack trace. This logger writes to a file called stacktrace.log in the root of your project.

However, you can quite easily override this default behavior to provide your own custom logger for unfiltered stack traces. Listing 12-7 shows an example configuration that logs all unfiltered stack traces to a rolling file appender.

Listitng 12-7. Logging Unfiltered Traces

log4j {
    appenders {
        rollingFile name:"stacktraceLog",
                        file:"/var/log/unfiltered-stacktraces.log",
                        maxFileSize:"1MB",
                        layout: pattern(conversionPattern: '%c{2} %m%n')
    }
    error stacktraceLog:"StackTrace"
}

You can also disable this functionality completely by passing the grails.full.stacktrace argument at the command line of your container or as an argument to the run-app command:

grails -Dgrails.full.stacktrace=true run-app

Externalized Configuration

During deployment, the Config.groovy file is compiled into a class and packaged into the WAR. Although this has its advantages, you may want to keep all configuration outside the main WAR file. For example, say you wanted to allow logging to be configured outside the application; to achieve this, you can use Grails' externalized configuration mechanism.

Essentially, within Config.groovy you can specify the grails.config.locations setting to contain a list of locations that need to be merged into the main configuration. Taking the logging example, Listing 12-8 shows how you could externalize the logging configuration to a file in the USER_HOME directory.

Listitng 12-8. Using Externalized Configuration

grails.config.locations = ["file:${userHome}/gtunes-logging.groovy"]

You can even allow the DataSource to be configured externally using this mechanism. Although DataSource.groovy and Config.groovy are separate files on the file system, Grails merges them into a single logical configuration object. Hence, you can externalize not just logging, or any configuration, but also the DataSource, as shown in Listing 12-9.

Listitng 12-9. Externalizing DataSource Configuration

grails.config.locations = ["file:${userHome}/.settings/gtunes-logging.groovy",
                           "file:${userHome}/.settings/gtunes-datasource.groovy"]

If you prefer to use static properties files in externalized configuration, you can do this too. Just use the extension. properties when referring to the files, and use regular java.util. Properties file semantics for configuration.

Understanding Grails' Build System

Grails' build system is powered by the Gant (http://gant.codehaus.org) build tool. Gant is a thin wrapper around Apache Ant (http://ant.apache.org), the ever-popular Java build system. Unlike Ant, which uses an XML format to describe a build, Gant uses a Groovy DSL. The benefit here is that you can easily mix build logic with scripting in Groovy code. Listing 12-10 shows a typical example of a Gant build script.

Listitng 12-10. An Example Gant Build Script

targetDir = "build"
target(clean:"Cleans any compiled sources"){
    delete(dir:targetDir)
}

target(compile:"The compilation task") {
    depends(clean)
    mkdir(dir:"$targetDir/classes")
    javac(srcdir:"src/java",
              destdir:"$targetDir/classes" )
}
target(jar:"Creates a JAR file") {
    jar(destfile:"$targetDir/app.jar",basedir:"$targetDir/classes")
}
target(dist:"The default task") {
   depends(compile, jar)
}
setDefaultTarget ( dist )

Notice how the example in Listing 12-10 defines a number of targets by calling the target method. These are equivalent to Ant's <target> tag. Also, as you can see, you can specify dependencies between targets using the depends method:

depends(compile, jar)

If you install Gant outside of Grails, Gant includes its own command-line interface via the gant command. The gant command will search for a file called build.gant, the same way Ant looks for build.xml, and attempt to call it if found. Using the gant command, you can call an individual target or chain them, as shown here:

$ gant clean jar

It's at this point that you'll begin to realize the differences between vanilla Gant and Grails. Although Gant behaves much like Ant, Grails wraps Gant in its own grails command—the same one you've been using throughout the book. The grails command uses conventions within a Grails project to try to automatically figure out which script to execute. For example, when you run the following command:

$ grails create-app

Grails will search the following directories for a Gant script called CreateApp.groovy to execute:

  • PROJECT_HOME/scripts:The scripts directory of the current project.
  • GRAILS_HOME/scripts:The scripts directory of the location where you installed Grails.
  • PLUGINS_HOME/*/scripts:Each installed plugin's scripts directory.
  • USER_HOME/.grails/scripts:The scripts directory within the .grails directory of the current user's home directory. The location of this is operating system dependent.

If a matching Gant script is found, the grails command will execute the default target of the Gant script. In contrast to the gant command, the grails command is optimized for Grails' project layout, for the plugin system, and for the easy use of passing arguments.

Creating Gant Scripts

To help you understand this better, let's take a look at a simple "Hello World"–style example. Using the grails create-script command, create a new script called HelloWorld.groovy:

$ grails create-script hello-world

As expected, you'll end up with a new Gant script in the called HelloWorld.groovy in the scripts directory of your project. Figure 12-1 shows the script sitting snugly in place.

Figure 12-1. The HelloWorld.groovy Gant script

image

Grails uses lowercase names separated by hyphens—for example, hello-world—when referencing scripts but transforms the name into camel case for the script name. Listing 12-11 shows the contents of the generated HelloWorld.groovy script from Figure 12-1.

Listitng 12-11. The Script Template

grailsHome = ant.project.properties."environment.GRAILS_HOME"

includeTargets << new File ( "${grailsHome}/scripts/Init.groovy" )

target(main: "The description of the script goes here!") {

    // TODO

}

setDefaultTarget(main)

As you can see, the template pulls in some existing functionality from a script called Init.groovy in the scripts directory of the location where you installed Grails. It then defines a single target, the default target, called main. To complete the "Hello World" example, you could use just a println statement or the echo target provided by Ant:

target(main: "The description of the script goes here!") {
    echo "Hello World!"
}

Now to run the hello-world script, all you need to do is run the following command using the grails executable:


$ grails hello-world
Welcome to Grails 1.1-SNAPSHOT - http://grails.org/
Licensed under Apache Standard License 2.0
...
Running script /Developer/grails-dev/book/dgg/code/ch12/scripts/HelloWorld.groovy
...
     [echo] Hello World!

Grails will perform a search of all the directories mentioned previously and find the HelloWorld.groovy script. Since the main target is the default target, Grails will execute it, which results in the "Hello World!" message being printed.

Of course, you have the entire Ant API at your disposal, which allows you to do a lot more than just print messages. Ant, and its plugins, provides access to targets that allow you to manipulate the file system, compile Java or Groovy code, perform XSLT transformations, and do just about anything you could dream of from the command line.


Tip It may be useful, if you aren't already familiar with it as most Java developers are, to take a look at the Apache Ant manual (http://ant.apache.org/manual/). It provides comprehensive information about what you can do with Ant.


Command-Line Variables

The Init.groovy script that was imported by HelloWorld.groovy in Listing 12-11 provides a bunch of useful variables and targets. These are some of the variables you may find useful:

  • grailsVersion:The version of Grails you're using
  • grailsEnv:The environment Grails is executing in
  • basedir:A String representing the base directory that the script is executing from
  • baseFile:Similar to basedir, but a java.io.File representation
  • userHome:The current user's home directory as a String
  • pluginsHome:The location where plugins are installed
  • classesDir:The location where classes are compiled to

The grailsEnv variable deserves special mention. If you recall from Chapter 2, you can tell Grails to run within the context of development, test, or production environments. As a recap, the following command will execute the run-app command using the production settings:

$ grails prod run-app

Your scripts can be equally environment-aware using the grailsEnv variable. For example, if you want a Gant script to run only in the development environment, you can write code like this:

if(grailsEnv == 'development') {
    // do something
}

Some of the other variables, such as the pluginsHome and classesDir variables, are automatically constructed by Grails. By default, Grails stores plugins and compiled resources in your USER_HOME directory under a special path. For example, you can find the gTunes application's compiled classes in the directory USER_HOME/.grails/1.1/projects/gTunes/classes. Figure 12-2 describes some of the tokens that make up this path.

Figure 12-2. Grails compilation paths

image

As you can see from Figure 12-2, Grails takes the Grails version number and the project name to formulate a path within the USER_HOME directory. If you are not happy with this location, then you can tell Grails to use a different path by passing the grails.work.dir argument at the command line:

$ grails -Dgrails.work.dir=/tmp run-app

In fact, you can pass a whole load of different command-line arguments to customize the different locations that Grails uses:

  • grails.work.dir:The base location where all Grails work occurs, including the test and source compilation directories
  • grails.project.classes.dir:The location where project sources are compiled to
  • grails.project.resource.dir:The location where project static resources (such as web.xml) are generated to
  • grails.project.test.class.dir:The location where test sources are compiled to
  • grails.plugins.dir:The location where plugins are installed
  • grails.global.plugins.dir:The location where global plugins are installed

Parsing Command-Line Arguments

Unlike raw Gant, the grails command doesn't support chaining of targets, instead favoring the easy passing of command-line arguments. One useful target to depend on that is provided by the Init.groovy script is called the parseArguments target. The parseArguments target will read any command-line arguments and produce a variable called argsMap containing the values of the arguments in a more accessible form.

For example, say you wanted to enable the HelloWorld.groovy script to be able to print the name of the person to say hello to in either uppercase or lowercase. You could allow the name to be passed as a command-line argument and whether to print in uppercase or not as a command-line flag, as follows:

$ grails hello-world John -uppercase

Implementing the handling of these arguments manually would be somewhat tricky. Luckily, if you depend on the parseArguments target, all the heavily lifting is done for you. Listing 12-12 shows an updated HelloWorld.groovy Gant script that gracefully handles these arguments.

Listitng 12-12. Handling Command-Line Arguments

depends(parseArguments)
def message = "Hello ${argsMap.params ? argsMap.params[0] : 'World'}"
if(argsMap.uppercase) {
    echo message.toUpperCase()
}
else {
    echo message
}

Notice that command-line flags (the arguments that start with - or --) are placed as boolean values into the argsMap. The example in Listing 12-12 shows how the -uppercase flag ends up as a boolean value with the key uppercase inside the argsMap. You can also have flags with values: for example, if you passed -uppercase=yes, then the value would be a String with the value yes in the argsMap.

All other arguments that are not flags are placed in the params key as a List that retains the order in which they were passed.

Documenting Your Scripts

You may have noticed from the script template in Listing 12-11 that the main target has a place holder for the description of the target:

target(main: "The description of the script goes here!") {

You can provide additional information about a target so that others understand better how to go about using your script. For example, to give information about the hello-world script, you could modify this as follows:

target(main: "Prints 'hello world' to System.out") {

Then whenever another user of your script needs to get help on how to use the script, they can use the help command provided by Grails, as shown in Listing 12-13.

Listitng 12-13. Getting Help from Gant Scripts


$ grails help hello-world
...
grails hello-world -- Prints 'hello world' to System.out

If one line of help is insufficient, you can take advantage of Groovy multiline strings to provide more detailed help, an example of which is shown in Listing 12-14.

Listitng 12-14. Using Multiline Strings to Provide Detailed Help

target(main: """Prints 'hello world' to System.out
Type 'grails hello-world <name>' to say hello to someone specific

Available Flags:

-uppercase: Prints the message in uppercase
""") {

Reusing More of Grails

The inclusion of the Init.groovy script shown in Listing 12-11 is just one example of including an existing Grails script. You can in fact include a whole array of different scripts that provide different features. For example, say you want to make sure the tests run before your script is executed. You can include the TestApp.groovy script and depend on the testApp target, as shown in Listing 12-15.

Listitng 12-15. Executing Grails' Tests

includeTargets << grailsScript("TestApp")
...
target(main: "The description of the script goes here!") {
    depends(parseArguments, testApp)
    ...
}

Alternatively, if you want to make sure that the container is up and running, maybe in order to perform some kind of automated functional tests, you can use the RunApp.groovy script. This script is the same one used when you type grails run-app at the command line, and it provides a target called runApp that you can use to load Grails' embedded Jetty container. As an extension to this, in the next section you'll look at how you can load Grails without even needing a container.

Bootstrapping Grails from the Command Line

If you need access to the Grails environment from the command line, you can load Grails using the GRAILS_HOME/scripts/Bootstrap.groovy script. This will enable you to, for example, use GORM from the command line for batch processing.

To get started, you need to include the Bootstrap.groovy script as follows:

includeTargets << grailsScript("Bootstrap")

and then call the bootstrap target:

bootstrap()

Once this is done, a number of new variables will be created including the following:

  • grailsApp:A reference to the org.codehaus.groovy.grails.commons.GrailsApplication class that allows you to inspect the conventions in a running Grails application.
  • appCtx:The Spring ApplicationContext instance that contains the bean definitions for the Grails application, as found at runtime.
  • servletContext:A mock implementation of the ServletContext, usable from the command line.
  • pluginManager:A reference to the org.codehaus.groovy.grails.plugins. GrailsPluginManager instance that allows you to inspect the currently installed plugins.

The most commonly used of these is the appCtx variable that allows access to all the beans contained within the Spring ApplicationContext. For example, if you need to obtain the Hibernate SessionFactory and/or SQL DataSource, you can easily do so using the appCtx:

DataSource dataSource = appCtx.getBean("dataSource")
SessionFactory sessionFactory = appCtx.getBean("sessionFactory")

With the basics out of the way, let's see a couple of examples of using Gant to boost your command-line productivity.

Gant in Action

Printing "Hello World!" to the command window is fun and all, but ultimately it not very useful. In the following sections, you'll be looking at a couple of real-world Gant scripts. The first is a script that will allow you to quickly deploy to Tomcat.

Automated Deployment to Tomcat

Writing a Tomcat deployment script in Ant is pretty trivial thanks to the targets that ship with Tomcat (see http://tomcat.apache.org/tomcat-6.0-doc/manager-howto.html). However, before you can start this example, you need to make sure you have Tomcat installed and TOMCAT_HOME set to the location where you installed it. Then run the grails create-script command as follows:

$ grails create-script tomcat-deploy

With that done, you should have a TomcatDeploy.groovy file in the scripts directory of your project, as shown in Figure 12-3.

Figure 12-3. The TomcatDeploy.groovy script

image

The TomcatDeploy.groovy script template will look identical to the HelloWorld.groovy template you saw earlier. To begin with, you're going to need to figure out the path to the Tomcat installation directory. Inspecting the TOMCAT_HOME environment variable can help you achieve this:

grailsHome = ant.project.properties."environment.GRAILS_HOME"
tomcatHome = ant.project.properties."environment.TOMCAT_HOME"

With knowledge of the Tomcat directory in hand, the next thing to do is include the War.groovy script available in GRAILS_HOME/scripts. The War.groovy template contains targets that allow you to construct a valid WAR file:

includeTargets << grailsScript("War")

To take advantage of the Tomcat Ant tasks, you have to define them by calling the taskdef method. This method relates to the <taskdef> target of Ant, so defining Ant tasks in Gant is pretty much identical to doing so in pure Ant—minus the angle brackets:

ant.path(id:"tomcat.lib.path") {
    fileset(dir:"${tomcatHome}/server/lib",includes:"*.jar")
}
ant.taskdef(name:"deploy",
            classname:"org.apache.catalina.ant.DeployTask",
            classpathref:"tomcat.lib.path")

As you can see, the only tricky part is ensuring that all the JAR files for the DeployTask class are placed onto the classpath appropriately using the JAR files available in your Tomcat installation directory. This is done using the classpathref named argument and a predefined Ant path called tomcat.lib.path.

Moving onto the main target of the TomcatDeploy.groovy script, you can change it to depend on the war target, which will ensure a valid WAR file is constructed before the rest of the code runs:

target(main: "Deploys the Grails application to Tomcat") {
    depends(parseArguments, war)     ...
}

Once that is done, you need to establish the destination to publish the WAR to. You could, for example, accept the destination as the first argument to the command and otherwise default to localhost:

def dest = argsMap.params ? argsMap.params[0] : "http://localhost:8080/manager"

Once that is done, the rest is left to the deploy target supplied by the org.apache.catalina.ant.DeployTask class:

deploy(war:warName,
       url:dest,
       path:serverContextPath,
       username:"deployer",
       password:"secret")

The warName and serverContextPath variables are set up by the War.groovy script, which you can reuse here. The deploy target also requires that you pass username and password arguments whenever deploying to Tomcat. Given that you have a running instance of Tomcat locally, if you run the tomcat-deploy target now, you'll probably get a 401 error such as the following:


java.io.IOException: Server returned HTTP response code: 401 for URL:
http://localhost:8080/manager/deploy?path=%2FgTunes

The reason is that currently Tomcat doesn't have a user called deployer with a password of secret registered with it. To do so, you need to edit the TOMCAT_HOME/conf/tomcat-users.xml file and add a user who has access to the Tomcat manager application, as shown in Listing 12-16.

Listitng 12-16. Adding a Tomcat Deployer

<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
  ...
  <user username="deployer" password="secret" roles="standard,manager"/>
</tomcat-users>

Once you have added the necessary Tomcat user, when you run the tomcat-deploy script, Grails will successfully deploy your application to Tomcat, as demonstrated in Listing 12-17.

Listitng 12-17. Deploying to Tomcat


$ grails tomcat-deploy
...
Done creating WAR /Developer/grails-dev/book/dgg/code/ch12/gTunes-0.1.war
   [deploy] OK - Deployed application at context path /gTunes

You can of course take this further and write another tomcat-undeploy script or even combine them into two scripts. Nevertheless, Listing 12-18 shows the full code for the TomcatDeploy. groovy scripts.

Listitng 12-18. The TomcatDeploy.groovy Script

grailsHome = ant.project.properties."environment.GRAILS_HOME"
tomcatHome = ant.project.properties."environment.TOMCAT_HOME"
includeTargets << grailsScript("War")
ant.path(id:"tomcat.lib.path") {
    fileset(dir:"${tomcatHome}/server/lib",includes:"*.jar")
}
ant.taskdef(name:"deploy",
                        classname:"org.apache.catalina.ant.DeployTask",
                        classpathref:"tomcat.lib.path")
target(main: "Deploys the Grails application to Tomcat") {
    depends(parseArguments, war)
    def dest = argsMap.params ? argsMap.params[0] : "http://localhost:8080/manager"
    deploy(war:warName,
           url:dest,
           path:serverContextPath,
           username:"deployer",
           password:"secret")
}
setDefaultTarget(main)
Exporting Data to XML

Another fairly common use of command-line scripts is to allow the migration of data. You could do this by performing a SQL dump of the database, but maybe you want to offer the ability to export all the content held in the database as XML as some web applications such as Atlassian Confluence and JIRA do.


Note Although Grails, as of this writing, doesn't ship with a general-purpose migration solution for performing database migrations, you may want to take a look at the LiquiBase plugin (http://www.liquibase.org/manual/grails) and/or the DBMigrate plugin (http://code.google.com/p/dbmigrate/wiki/Grails), which both offer solutions to this problem.


Let's start by considering how you would write an export script that dumped all the relevant data from the gTunes application into a single parseable XML document. First you'll need to create a new Gant script called export-library-to-xml:

grails create-script export-library-to-xml

With that done, you're going to need to take advantage of the GRAILS_HOME/scripts/ Bootstrap.groovy script we discussed earlier. To do so, simply change the import of the Init.groovy script to Bootstrap.groovy:

includeTargets << grailsScript("Bootstrap")

Inside the main target, you then need to depend on the parseArguments and bootstrap targets:

depends(parseArguments, bootstrap)

First, using the mechanics of the parseArguments target, you can work out the file to export to by either taking the first argument or creating a name programmatically:

def file = argsMap.params ?
               new File(argsMap.params[0]) :
               new File("./gtunes-data-${System.currentTimeMillis()}.xml")

As mentioned previously, the bootstrap target will set up a grailsApp variable that holds a reference to the GrailsApplication instance. The GrailsApplication instance can be used to dynamically load classes using the classLoader property. You need to do this because Gant scripts cannot directly reference the classes in your application, because they can't know whether those classes have been compiled yet. Luckily, it is pretty trivial to obtain a reference to any class using the classLoader:

def Artist = grailsApp.classLoader.loadClass("com.g2one.gtunes.Artist")

Unlike Java, with Groovy you can invoke any static method using a reference to java. lang.Class; hence, you can use regular GORM methods easily even with a dynamically loaded class reference. The first example of this is using the static count() method to figure out how many artists there are:

def artistCount = Artist.count()

Now it's time to create the XML. To do so, you're going to use Groovy's StreamingMarkupBuilder class. Listing 12-19 shows how to construct and use StreamingMarkupBuilder.

Listitng 12-19. Using StreamingMarkupBuilder to Write to a File

new FileWriter(file) << new groovy.xml.StreamingMarkupBuilder().bind {
    music {
        ...
    }
}

Builders in Groovy allow you to construct hierarchies of nodes, a concept that fits nicely into the construction of XML. In this case, the music method will become the root element <music> of the XML document. In the next step, you initiate a transaction using the withTransaction method first discussed in Chapter 10.

The reason for using a transaction here is so that a common Hibernate Session is shared for the remainder of the code, hence avoiding a LazyInitializationException occurring when accessing uninitialized associations. Unlike in the server environment, Grails does not do any management of the Hibernate Session for you in scripts, but using withTransaction you can circumvent that:

Artist.withTransaction {
    ...
}

As well as withTransaction, you're going to take advantage of the withSession method to obtain a reference to the Hibernate Session object used. As discussed in Chapter 10, when reading a large amount of data into the Hibernate Session, you may run out of memory if you don't periodically clear the Session, and since you don't exactly know how much data is in the database, you're going to be doing that here:

Artist.withSession { session ->
    ...
}

The next step, if you'll excuse the pun, is to use the step method using the previously obtained artistCount variable to perform pagination of records. With this technique, you can obtain, say, ten Artist instances, including associations; manipulate them in some way; and then clear the Session before loading the next ten. Listing 12-20 shows the code in action.

Listitng 12-20. Using the step Method to Paginate Records

0.step(artistCount, 10) { offset ->
    def artistList = Artist.list(offset:offset, max:10, fetch:[albums:'join'])
    ...
    session.clear()
}

With a list of Artist instances in hand, now it's just a matter of iterating over each one to create a bunch of <artist> XML elements:

for(currentArtist in artistList) {
    artist(name:currentArtist.name) {
        ...
    }
}

Finally, you also need to include all the Album instances associated with each Artist and all the Song instances associated with each Album. You can achieve this with a couple more nested loops:

for(currentAlbum in currentArtist.albums) {
    album(currentAlbum.properties['title', 'year', 'genre', 'price']) {
        for(currentSong in currentAlbum.songs) {
            song(currentSong.properties['title', 'duration'])
        }
    }
}

Notice how you can reference a subset of each Album instance's property values using the subscript operator and a List of property names:

currentAlbum.properties['title', 'year', 'genre', 'price']

And with that, the export-library-to-xml script is complete. Listing 12-21 shows the full code listing for the export-library-to-xml Gant script.

Listitng 12-21. The Full export-library-to-xml Code

grailsHome = ant.project.properties."environment.GRAILS_HOME"
includeTargets << new File ( "${grailsHome}/scripts/Bootstrap.groovy" )
target(main: "Exports the gTunes library contained within the database to XML") {
    depends(parseArguments, bootstrap)
    def file = argsMap.params ?
                   new File(argsMap.params[0]) :
                   new File("./gtunes-data-${System.currentTimeMillis()}.xml")
    def Artist = grailsApp.classLoader.loadClass("com.g2one.gtunes.Artist")
    def artistCount = Artist.count()
println "Creating XML for $artistCount artists"
new FileWriter(file) << new groovy.xml.StreamingMarkupBuilder().bind {
    music {
        Artist.withTransaction {
            Artist.withSession { session ->
                0.step(artistCount, 10) { offset ->
                    def artistList = Artist.list(offset:offset,
                                                          max:10,
                                                          fetch:[albums:'join'])
                    for(currentArtist in artistList) {
                        artist(name:currentArtist.name) {
                            for(currentAlbum in currentArtist.albums) {
                                album(currentAlbum.properties['title', 'year',
                                                           'genre', 'price']) {
                                   for(currentSong in currentAlbum.songs) {
                                       song(currentSong.properties['title',
                                                           'duration'])
                                   }
                                 }
                               }
                            }
                          }
                          session.clear()
                      }
                 }
             }
         }
      }
      println "Done. Created XML export ${file.absolutePath}"
  }
  setDefaultTarget(main)

As you can see from the full code in Listing 12-21, you can also add a couple of println statements just to inform the user what is going on. You can now run the export-library-to-xml script using the grails command, and out will pop an XML document, as shown in Listing 12-22.

Listitng 12-22. Running the export-library-to-xml Script


$ grails export-library-to-xml
...
Creating XML for 4 artists
Done. Created XML /Developer/grails-dev/gTunes/gtunes-data-122224970.xml

As you can see in this example, the script produces a file called gtunes-data-122224970.xml. The contents of this file contain the XML built by StreamingMarkBuilder; Listing 12-23 shows an example.

Listitng 12-23. Example Output XML


<?xml version="1.0"?>
<music>
    <artist name="The Killers">
         <album year="2006" title="Sam's Town" price="4.99" genre="Rock">
               <song title="Sam's Town" duration="246099"/>
               <song title="Enterlude" duration="49972"/>
               <song title="When You Were Young" duration="220499"/>
               ...
        </album>
    </artist>
       ...
</music>

Integration with Apache Ant

As discussed already, Grails' build system Gant builds on Ant. However, it may be a requirement for your organization to support a pure Ant build. If so, you have a number of options at your disposal. The first, and simplest, option is to use the build.xml file that is present in the root of every Grails project. This build.xml file simply delegates to Grails commands and hence relies on a copy of Grails being installed. Listing 12-24 shows an example of running the test target and the tests failing!

Listitng 12-24. Running a Target in the build.xml File


$ ant test
Buildfile: build.xml

test:

    ...
     [exec] Running script /Developer/grails/scripts/TestApp.groovy

    ...
     [exec] Tests failed: 6 errors, 0 failures, 0 compilation errors.

       View reports in /Developer/grails-dev/gTunes/test/reports

BUILD FAILED
/Developer/grails-dev/gTunes/build.xml:30: exec returned: 1

Total time: 1 minute 9 seconds

As you can see from Listing 12-24, the build.xml file uses the Ant <exec> target to simply delegate responsibility to the grails command. Another approach to integrating Ant and Grails is to use the GRAILS_HOME/src/grails/grails-macros.xml file, which defines a <grails> macro target for calling Grails commands.

You can include the grails-macros.xml file in any normal Ant build using an Ant <import>:

<property environment="env" />
<import file="${env.GRAILS_HOME}/src/grails/grails-macros.xml"/>

In this example, you're using the location within GRAILS_HOME, but you could copy it to a more convenient location in your build if necessary. With that done, you can now use the new <grails> macro target to call Grails commands:

<grails command="test-app" />

The <grails> command works by looking up the appropriate classes from GRAILS_HOME. If the build environment you're working with doesn't have a GRAILS_HOME, then you'll need to use the <extend-classpath> element to tell the <grails> target where to look for the Grails JARs, as shown in Listing 12-25.

Listitng 12-25. Using the <extend-classpath> Element

<grails command="run-app">
    <extend-classpath>
      <fileset dir="${lib.dir}"/>
    </extend-classpath>
</grails>

If you need to pass arguments to the <grails> command, you can use the args attribute. For example, the following usage will use Grails' test-app command to run the UserControllerTests unit test:

<grails command="test-app" args="UserController" />

Finally, if you need to pass system properties to the Grails command, such as to change the server port, you can do so with the <sysprops> element, as shown in Listing 12-26.

Listitng 12-26. Using the Element to Pass System Properties

<grails command="run-app">
    <sysprops>
        <sysproperty key="server.port" value="7070"/>
    </sysprops>
</grails>

Dependency Resolution with Ivy

Apache Ivy is a dependency manager for Ant. With Ivy you can specify the JAR dependencies of your project in XML format. Your build then automatically downloads these dependencies. You can integrate Ivy into Grails in a couple of ways. One way is to just use the Ant build.xml file and integrate Ivy using the standard way described on the Ivy web site at http://ant.apache.org/ivy/history/latest-milestone/tutorial/start.html.

However, there is also a plugin for Grails that quickly integrates Ivy with Grails. To get started, you need to run the install-plugin command as follows:

grails install-plugin ivy

This installs Ivy for you locally without you having to download the Ivy distribution yourself. It will also automatically create the ivy.xml and ivyconf.xml files, both of which are necessary for transitive dependency resolution with Ivy. Figure 12-4 shows the two files nestled within the root directory of the target project.

Figure 12-4. The Ivy configuration files

image

The ivyconf.xml file allows you to specify one or more resolvers to resolve dependencies. Typically you can leave this file alone, because you'll need to modify it only if you plan to configure additional repositories or even host your own repositories. The ivy.xml file is used to define the actual dependencies. Currently, the gTunes application defines a few dependencies that are contained in the lib directory, as shown in Figure 12-5.

Figure 12-5. Current JAR dependencies

image

Some of these, like the Amazon JAR, won't necessarily be available in the repositories that Ivy scans. As mentioned, to make these available somewhere, you could host your own repositories and configure ivyconf.xml appropriately. Nevertheless, Listing 12-27 shows an example of configuring ivy.xml to resolve dependencies in the gTunes application.

Listitng 12-27. Configuring ivy.xml

<ivy-module version="1.0">
   <info organization="codehaus" module="grails"/>
   <dependencies>
        <dependency org="commons-codec" name="commons-codec" rev="1.3"/>
        <dependency org="commons-httpclient" name="commons-httpclient" rev="3.1"/>
        <dependency org="mysql" name="mysql-connector-java" rev="5.1.6"/>
            ...
    </dependencies>
</ivy-module>

Ivy has the ability to use Maven repositories to resolve dependencies, and as you can see, you can use a similar format to the Maven pom.xml file to specify dependencies on the ivy.xml file. With the ivy.xml file configured, you can then download dependencies using the get-dependencies command:

grails get-dependencies

Listing 12-28 shows the output from Ivy as it automatically resolves and downloads the necessary dependencies.

Listitng 12-28. Example Output from Ivy


[ivy-retrieve] :: resolving dependencies :: codehaus#grails;working@graeme...
[ivy-retrieve]          confs: [default]
[ivy-retrieve]          found commons-codec#commons-codec;1.3 in public
[ivy-retrieve]          found commons-httpclient#commons-httpclient;3.1 in public
[ivy-retrieve]          found commons-logging#commons-logging;1.0.4 in public
[ivy-retrieve]          found mysql#mysql-connector-java;5.1.6 in public
[ivy-retrieve] ::     resolution report :: resolve 277ms :: artifacts dl 8ms
[ivy-retrieve]          ::          evicted modules:
[ivy-retrieve]          commons-codec#commons-codec;1.2 by [commons-codec#figs/U002.jpg
                                                commons-codec;1.3] in [default]
             ---------------------------------------------------------------------
             |                  |           modules           ||  artifacts  |
             |        conf        | number| search|dwnlded|evicted|| number|dwnlded|
             ---------------------------------------------------------------------
             |       default      |   5   |   0   |   0   |   1   ||  6  |  0  |
             ---------------------------------------------------------------------
[ivy-retrieve] :: retrieving :: codehaus#grails
[ivy-retrieve]      confs: [default]
[ivy-retrieve]      conflict on /Developer/grails-dev/book/dgg/code/ch12/lib/figs/U002.jpg
                                           commons-codec-1.3.jar in [default]: 1.3
won
[ivy-retrieve]      0 artifacts copied, 4 already retrieved (0kB/12ms)

Now we'll cover how to integrate code coverage reporting into a Grails application.

Code Coverage with Cobertura

Even if you are an avid Test-Driven Development (TDD) practitioner, writing unit tests without knowing what code is covered by tests and what is not is a bit like shooting in the dark. Code coverage reports are incredibly useful because they will tell you what lines of code are covered by your unit tests and help you make an informed decision on what test you should be writing next. You'll often hear agile teams talking about improving their coverage. This decision is based on the analysis of coverage reports.

Out of the box, Grails does not produce code coverage reports, but thanks to the code-coverage plugin, it is easy to integrate the generation of code coverage reports into your application. To get started, as usual run the install-plugin command to install the code-coverage plugin:

$ grails install-plugin code-coverage

With that done, you can then run the test-app-cobertura command, which uses Cobertura (http://cobertura.sourceforge.net/), a code coverage tool for Java, to produce coverage reports. Cobertura uses byte code instrumentations and hence will slow down the running of your tests, but it will produce a nice set of reports in the test/reports/cobertura directory for you. Figure 12-6 shows an example.

Figure 12-6. A Cobertura coverage report

image

You can click any of the class names in the report in Figure 12-6 to get line-by-line coverage information. As you can see, you still have some work to do to improve the coverage of the gTunes application. However, it is important to note that you may have 100 percent coverage and still have holes in your unit tests. Code coverage should be used to show the areas of code that need testing, not as a sign of test completeness.

Since coverage reports may take a while to produce, you don't want to have to create them every time you run your test suite. It may be better to delegate this responsibility to a build server. In the next section, we'll cover how to set up continuous integration to achieve this.

Continuous Integration with Hudson

Agile and test-driven philosophies have been debated endlessly and are a subject beyond the scope of this book. Nevertheless, if there is one agile practice that would bring immediate benefits to any project, whether "traditional" or agile, it is continuous integration.

Continuous integration involves setting up a server that continuously (either on a schedule or through monitoring for changes) builds the latest code, runs any tests, and produces a snapshot of the code for distribution. The continuous integration server can perform all manner of additional tasks from producing coverage reports to creating the latest documentation and even sending e-mails or SMS messages to notify of build failures.

In this section, we'll demonstrate how to use Hudson, an open source continuous integration server available at https://hudson.dev.java.net/. To get started, you need to download the hudson.war distribution of Hudson and deploy it to a container such as Apache Tomcat. Deployment with Tomcat is a simple matter of dropping the WAR into the TOMCAT_HOME/ webapps directory and firing up Tomcat.

Then you can go to http://localhost:8080/hudson, assuming Tomcat is up and running on port 8080, and you'll be presented with the Hudson Dashboard shown in Figure 12-7.

Figure 12-7. The Hudson Dashboard

image

The next step is to install the Grails plugin for Hudson. From the main Dashboard screen, click the "Manage Hudson" link, and then click the "Manage Plugins" link. On the Available tab, select the check box next to the Grails plugin, and click the "Install" button at the bottom of the page. Once you have installed the plugin, you'll need to restart Hudson.

Once the Grails plugin is installed, the next step is to configure your Grails installations in Hudson. The plugin does not come with its own version of Grails. The plugin uses a version of Grails that must be installed on the system separately from Hudson. The plugin allows you to configure as many different versions of Grails as you like. This is useful if you are building multiple Grails projects in the same Hudson instance and not all of those Grails projects are built with the same version of Grails.

To configure your Grails installations in Hudson, click the "Manage Hudson" link on the main Dashboard screen, and then click the "Configure System" link. Figure 12-8 shows the part of this screen that is used to configure your Grails installations.

Figure 12-8. Configuring Grails installations in Hudson

image

You can see that each Grails installation has a name and a GRAILS_HOME. The name is simply an identifier that will help you select a particular version of Grails later when configuring jobs. The value of GRAILS_HOME must point to a specific Grails installation directory. Notice that there is validation built in to let you know whether the directory you have entered does not exist. The validation is not activated until you tab out of the text field.

Once you have configured all your Grails installations, make sure you scroll all the way to the bottom of the page and click the "Save" button.

With at least one Grails installation configured in Hudson, you are ready to create a job for a Grails project. You create a job for a Grails project in the same way you would for any other project in Hudson. From the main Dashboard screen, click the "New Job" link. Most often you will be creating a job for a so-called free-style software project, so you will select that radio button on the form to create a new job. See Figure 12-9.

Figure 12-9. Creating a new free-style job

image

Once you click the "OK" button, you will be taken to the page where you configure all the details for how this build will be carried out. This page allows you to define which version control system you are using, paths to the project, a schedule for building the project, and so on. Near the bottom of the page is where you will configure the actual build steps. Once the Grails plugin is installed, a new build step should show up labeled "Build With Grails," as shown in Figure 12-10.

Figure 12-10. The "Build With Grails" build step

image

When you select the "Build With Grails" build step, the page will be updated with a form, which lets you configure the Grails build. This will include at a minimum specifying a version of Grails to use and which Grails targets to execute. A typical target to execute is the test-app target, but you can configure your job to execute whichever targets make sense. Figure 12-11 shows the details of a Grails build.

The "Grails Installation" drop-down will include all the Grails installations you configured earlier. Select the version of Grails that this job should be built with.

The "Targets" field lets you specify as many targets as you would like to be executed as part of this build. The targets will be executed in the order that they are specified in this text box. If any arguments are to be passed to any particular target, then the target name and the arguments should be surrounded by double quotes so the plugin knows to group them as one command.

There are fields for specifying the grails.work.dir and project.work.dir system properties.

The "Project Base Directory" field will typically be left blank but is important if the Grails project is not at the root of the job's working directory. For example, if your Grails project is in your SCM system at a path like /projects/development/code/grails/gTunes/ and for some reason you need to configure this job to check out everything under /projects/development/code/ grails/gTunes/, then you will need to specify a value for the "Project Base Directory" field. The problem here is that the job root is /projects/development/code/grails/gTunes/, so the plugin will execute all Grails commands from that directory. Since that isn't the root of the Grails project itself, all the Grails commands will fail. To support this scenario, the "Project Base Directory" field should be given a value of /projects/development/code/grails/gTunes/, which is a relative path from the job root directory down to the root of the Grails project. With that in place, all of the Grails commands will be executed from the /projects/development/ code/grails/gTunes/ directory.

Figure 12-11. Configuring a Grails build

image

All other aspects of configuring a Grails job in Hudson are no different than they are for any other type of project.

Adding Support to Your Favorite IDE

Java developers in general have become particularly reliant on the comfort of modern integrated development environments (IDEs). This is largely because of the strictness of the Java language. From its static typing rules to quirks like its insistence on semicolons at the end of each line of code, it is hard to write anything in Java without a little nagging from the compiler. Fortunately, modern IDEs such as Eclipse and IntelliJ have made life a lot easier. In fact, they've done more than that. With the advent of refactoring tools, Java has become one of the most maintainable languages out there.

The tools in the dynamic language space are in general nowhere near as advanced as those available for Java. On the other hand, many developers create entire applications in simple text editors such as TextMate and jEdit, preferring their speed and efficiency to the relative clunkiness and slowness of a robust, richly featured IDE. This is possible because of the simplicity of frameworks such as Grails and the relatively forgiving Groovy grammar. It is our view that you can certainly get away with using the simpler tools during the early days of an application's life cycle.

However, as the application grows and enters the maintenance phase, the need for an IDE will also grow—particularly for refactoring and maintenance. Fortunately, although the tooling is much younger, you do have options available to you, which we will be covering in the following sections.

IntelliJ

By far the most complete IDE for Grails available at the moment is JetBrains' IntelliJ IDEA with the JetGroovy plugin installed. JetBrains worked closely with the Groovy team to make it the best possible environment to develop Groovy and Grails applications. In addition, although IntelliJ is a commercial IDE, JetBrains embraced the open source nature of Groovy by contributing back to the community. The joint compiler built into Groovy that allows Java and Groovy classes to be compiled together was contributed to Groovy during the development of JetGroovy.

JetGroovy contains the most complete support for code completion available for Groovy, performing completion on all statically typed references. Using type inference, JetGroovy can even sense completions on many dynamically typed references. JetGroovy also includes full circular refactoring, so if you rename a method in a Java source, it's picked up on the Groovy side. Likewise, if you rename a method in a Groovy source, all the Java code referencing that method changes accordingly.

JetGroovy will also complete all the dynamic methods added by Groovy at runtime, and you get many of the inspectors and quick fixes Java developers have come to expect. We recommend you take a look at the excellent marketing material JetBrains has put together on JetGroovy, which describes the features available in detail, at http://www.jetbrains.com/idea/features/groovy_grails.html. You can find even more documentation on JetGroovy on the Grails web site at http://www.grails.org/IDEA+Integration. Figure 12-12 shows the IntelliJ IDEA with JetGroovy in action.

Figure 12-12. IntelliJ IDEA with the JetGroovy plugin

image

NetBeans

Of the open source IDEs available, NetBeans (http://www.netbeans.org/) provides the most advanced support for Groovy and Grails development. After making NetBeans one of the best Ruby IDEs on the market, Sun began investing in Groovy and Grails support, and with the release of NetBeans 6.5, the results of that investment have really begun to show. Featuring built-in Groovy support, the NetBeans plugin provides syntax highlighting, code completion, outline views, and menu options to easily access Grails commands. Figure 12-13 shows what NetBeans' Groovy editor looks like.

Figure 12-13. NetBeans Groovy/Grails integration

image

There is a good write-up on what is currently available in NetBeans on the Grails web site at http://www.grails.org/NetBeans+Integration.

Eclipse

The Eclipse plugin is available from the Groovy web site at http://groovy.codehaus.org/Eclipse+Plugin where there are instructions on how to install it. It is still under active development, so we recommend retrieving it from Groovy's Subversion repository, building it, and installing it according to the instructions on the site. This will allow you to get the most benefit out of the currently implemented features. Alternatively, Groovy's update page is kept reasonably up-to-date.

The installation process with Eclipse is merely to drop the plugin ZIP file into the plugins directory located within your Eclipse installation. Once this is complete, just restart the IDE, and the plugin will be activated. There is one little bit of configuration to perform. The Groovy Eclipse plugin performs its own compilation process by default. This can get in the way of the Grails-configured compiler, so you should disable this feature by selecting Project figs/U001.jpg Properties figs/U001.jpg Groovy Project Properties and checking the "Disable Groovy Compiler Generating Class Files" box.

Importing a Grails Project

Once you have the plugin installed, the next step is to import your Grails project. Luckily, Grails automatically creates Eclipse project and classpath files for you when you create the project. So, to import the project, right-click within the Package Explorer, and select the Import option, at which point the dialog box shown in Figure 12-14 will appear.

Figure 12-14. Importing a Grails project into Eclipse

image

Select the "Existing Projects into Workspace" option, and click the "Next" button. Now browse to the root of a Grails project using the "Browse" button, and click "Choose" or "OK." Once you have chosen the directory where the project is located, Eclipse will automatically detect that there are Eclipse project files within the specified root directory and even in subdirectories within the root. The result is that Eclipse displays a list of projects that you can import, as shown in Figure 12-15.

Figure 12-15. Importing a Grails project into Eclipse

image

Select the Grails project you want to import, and click the "Finish" button to complete the import. Don't be surprised that the Grails project you imported appears in the Package Explorer as "not compiling" and the Problems view contains a number of entries. Once the import is complete, there is one final step. Every Grails Eclipse project anticipates the existence of a GRAILS_HOME Eclipse variable; to create this (if it doesn't already exist), perform the following steps:

  1. Right-click the project, and select Properties.
  2. Select Java Build Path on the left menu.
  3. Click the Libraries tab.
  4. Click the "Add Variable" button.
  5. Click the "Configure Variables" button.
  6. Within the dialog box that appears, click "New."
  7. Enter GRAILS_HOME into the "Name" field.
  8. Click the "Folder" button, and browse to the location where Grails is installed.
  9. Keep clicking OK until the changes are applied through all dialog boxes.

At this point, your project will be configured with the correct source directories and class-path. In the next section, we'll show how you can configure Grails as an external tool so that you can run a Grails application embedded within the IDE.

Running a Grails Application from Eclipse

You can run a Grails application from Eclipse using the Eclipse "External Tools" support. In the "External Tools" drop-down list, click "External Tools," as shown in Figure 12-16.

Figure 12-16. Configuring an external tool for Grails in Eclipse

image

Then under the Main tab, point the "Location" field to the grails executable, which is GRAILS_HOME/bin/grails on Unix or GRAILS_HOME/bin/grails.bat on Windows. Then set the "Working Directory" field to the location of your project within the Eclipse workspace. Finally, you can specify which Grails command to run using the "Arguments" field. Figure 12-17 shows an example configuration.

You'll also need to set the GRAILS_HOME environment variable to the location where you installed Grails on the Environments tab. Once this is done, you can click the "Run" button in the bottom right of the dialog box shown in Figure 12-17. Eclipse will run your Grails application, and you'll see the output in the Eclipse console.

Figure 12-17. The External Tools dialog box

image

TextMate

If you happen to be lucky enough to work on a Mac (cue flame wars!), then you can take advantage of the excellent support for Groovy and Grails in the TextMate (http://macromates.com/) text editor. TextMate is a commercial text editor that is ultrafast, is extensible, and features nice features such as macros for pseudocode completion.

It also has really good integration with command-line processes and can be used as a complete replacement for Vi (http://en.wikipedia.org/wiki/Vi). On the downside, as mentioned, it is commercial and runs only on the Mac, but there are other great editors available that work with Grails, such as jEdit (http://www.jedit.org/), that are cross platform.

To get going, install TextMate, and then grab the TextMate bundles for Groovy and Grails from the TextMate repository at http://macromates.com/svn/Bundles/trunk/Bundles/. Typically you can just check these out using Subversion as follows:

svn co http://macromates.com/svn/Bundles/trunk/Bundles/Groovy.tmbundle/
svn co http://macromates.com/svn/Bundles/trunk/Bundles/Groovy%20Grails.tmbundle/

And then from Finder, simple double-click each one to install the bundle. Depending on your version of TextMate, there may be further steps; it is worth checking the http://manual.macromates.com/en/bundles#getting_more_bundles page for the latest instructions if anything happens to go wrong. Once you have TextMate up and running, it's advisable to install the Terminal integration by selecting Help figs/U001.jpg Terminal Usage and then clicking the "Create Link" button.

Once this is done, you can easily create a TextMate project from any directory via Terminal using the mate command. For example, from the root of the gTunes application, you can type this:

$ mate.

And like magic, you'll have a TextMate project ready to go. You can then open any unit test case, such as UserControllerTests, for example, and use the key combination Ctrl+Shift+Cmd+G to invoke the Grails menu. From this menu, you can choose to run the current test, all tests, or even the application. Figure 12-18 shows TextMate in action with the Grails context menu.

Figure 12-18. The Grails context menu in TextMate

image

If you choose to run all the tests, a new window will pop up and give you nicely formatted output of the test run, highlighting failed tests in red and good tests in green! Figure 12-19 shows the GrailsMate window that facilitates execution of tests in this manner.

Figure 12-19. Running tests in TextMate

image

Another useful shortcut is Alt+Cmd+down arrow, which brings up the "Go to" option to quickly jump between resources that follow the same convention. For example, if you are editing the UserController class and you use the "Go to domain class" option, TextMate will open the User domain class by convention. Beyond these useful commands, there is a whole bunch of snippets that can be accessed by typing a shortcut and then hitting the Tab key. For example, you can type rv and then hit Tab, and you get the | character, indicating the location of your cursor, placed in a convenient location:

render(view:"|")

It is worth taking a look at the Bundlesfigs/U001.jpgGroovy and Bundlesfigs/U001.jpgGroovy Grails menus to see what is available because there are many useful shortcuts and commands that you can take advantage of. In our experience, if you're looking to get the best out of Grails' agile nature, it is worth using a simple text editor like TextMate as a complement to your regular IDE, whether it be IntelliJ, Eclipse, or NetBeans. It is very much the agile way to use the simplest possible tools to complete a job, and this applies to IDEs as well. You might even find Vi is good enough!

Remote Debugging with an IDE

You can remote debug Grails by running the grails-debug executable as a substitute for the grails executable.


Tip The grails-debug executable simply sets up the necessary Java options to start Grails with a remote debugger. You could configure these yourself by setting the JAVA_OPTS environment variable.


The grails-debug executable will start Grails with a debug JVM. The debugger is listening on port 5005, which is the default debugger port for Java. You can then create a remote debug configuration in your IDE. For example, to do this with IntelliJ IDEA, you would go to the Debug menu and click Edit Configurations. Then click the plus icon in the top left and choose "Remote," which will give you a remote debug configuration, as shown in Figure 12-20.

Figure 12-20. An IntelliJ remote debug configuration

image

You can leave the remaining settings as they are and just click the "OK" button in the bottom-right corner. With that done, just select the remote debug configuration and hit the "Debug" button, and IntelliJ will connect to the Grails remote server. You can then set breakpoints in your applications sources, and IntelliJ will stop at those points.

If you're willing to be adventurous, you can add Grails' source code to your path and step into the internals of Grails, but we'll leave that decision up to you! With IDEs out of the way, we're now going to talk about how you integrate Grails into the server environment. From mail servers to containers, there is still much to cover, so don't go away.

Integration with E-mail Servers

It has become a frequent use case for web applications to send e-mails. The Simple Mail Transfer Protocol (SMTP) is the enabler for mail delivery and has become pretty much the de facto standard for outgoing e-mail. A number of different server products support SMTP, from Microsoft Exchange Server to the open source Sendmail agent that is available on most Unix systems.


Note The configuration of an SMTP server is beyond the scope of this book; we will show you how to set up Grails to talk to a successfully configured mail server.


You can integrate mail with Grails in several ways. Since Grails is built on Spring, you could use the org.springframework.mail abstraction, which provides a nicer API than JavaMail (http://java.sun.com/products/javamail/). However, that involves a lot of manual configuration, so what we'll be demonstrating is how to integrate the Grails Mail plugin into your application to enable the sending of confirmation e-mails whenever a user registers on gTunes or makes a purchase.

To get started, you need to install the Mail plugin with the install-plugin command:

$ grails install-plugin mail

The Mail plugin already comes with JavaMail and its dependencies, so you don't need to install any more libraries or dependencies. It uses sensible defaults and automatically assumes your mail server is running locally on port 25. However, if this is not the case, you can configure it using some settings in grails-app/conf/Config.groovy. For example, Listing 12-29 shows how you could configure the mail server to send e-mails using a Gmail account instead.

Listitng 12-29. Configuring the Mail Plugin

grails {
   mail {
     host = "smtp.gmail.com"
     port = 465
     username = "[email protected]"
     password = "yourpassword"
     props = ["mail.smtp.auth":"true",
              "mail.smtp.socketFactory.port":"465",
              "mail.smtp.socketFactory.class":"javax.net.ssl.SSLSocketFactory",
              "mail.smtp.socketFactory.fallback":"false"]
   }
}

Notice in Listing 12-29 the usage of the props setting, which allows you to configure the properties of the JavaMail framework. However, for our purposes, we'll assume that a mail server running locally is good enough. Returning to the Mail plugin itself, the main addition is a new method called sendMail added to all controllers. Listing 12-30 shows an example of its usage at its simplest.

Listitng 12-30. Sending a Simple Mail Message

sendMail {
    to "[email protected]"
    subject "Hello John"
    body "How are you?"
}

If you need to access the sendMail method from other places in your application, such as tag libraries and services, the Mail plugin provides a mailService that is available via dependency injection. Simply define a property called mailService in your tag library or service as follows:

def mailService

The sendMail method can then be called using the mailService instance, for example:

mailService.sendMail {
    ...
   }

In the example in Listing 12-30, a simple String is used for the body of the e-mail. However, it is equally possible to use a GSP view to define the body, which is something you'll be doing to send registration confirmation e-mails to users of the gTunes application. Before you can do so, however, you need to modify the User domain class in order to add a new email property. Listing 12-31 shows the change to the User class.

Listitng 12-31. Adding an email Property to the User Class

class User {
    String email
    ...
    static constraints = {
        ...
        email email:true, blank:false, unique:true
    }
}

As you can see in Listing 12-31, you've also applied a set of constraints to the email property. The email constraint ensures that it is a valid e-mail address, the blank constraint makes sure blank values are not allowed, and the unique constraint ensures that two users can't register with the same e-mail address. With this done, you need to modify the grails-app/views/user/register.gsp view to add a field for the email property to the registration form. Listing 12-32 shows the necessary change to the register.gsp file.

Listitng 12-32. Adding a Text Field for the email Property

<g:form action="register" name="registerForm">
    ...
    <div class="formField">
        <label for="login">Email:</label>
        <g:textField name="email" value="${user?.email}"></g:textField>
    </div>
    ...
</g:form>

With that done, you now have an e-mail address to send confirmation e-mails to! To send an e-mail, you'll need to modify the register action of the UserController class to use the sendMail method to deliver an e-mail. Listing 12-33 shows the changes to the register action.

Listitng 12-33. Sending an E-mail Confirmation

def register = {
        ...
            else if(u.save()) {
                session.user = u
                try {
                    sendMail {
                        to u.email
                        subject "Registration Confirmation"
                        body view:"/emails/confirmRegistration",
                            model:[user:u]
                    }
                }
                catch(Exception e) {
                    log.error "Problem sending email $e.message", e
               }
               redirect(controller:"store")
           }
    ...
}

Notice how in Listing 12-33 you can use the view argument of the body method to define the name of the GSP view used to render the e-mail. As you can see, you can also pass a model with the model argument. The code is wrapped in a try/catch block just in case there is a problem sending the confirmation mail. At the moment, the code simply logs the error, but you could place the message into a queue to be re-sent later using a scheduled job—something you'll be looking at in the next section.

As for the GSP itself, you need to create a new view at the location grails-app/views/emails/confirmRegistration.gsp. The example in Listing 12-33 uses an absolute path to this location. If you don't specify an absolute path then, as with regular views, the path is assumed to be relative to the current controller. Listing 12-34 shows the confirmRegistration view that renders the e-mail contents.

Listitng 12-34. The confirmRegistration View

<%@ page contentType="text/plain"%>
Dear ${user.firstName} ${user.lastName},

Congratulations! You have registered with gTunes, giving you access to a huge
collection of music.

Your login id is: ${user.login}

You can use the following link to login: <g:createLink controller="store"
                                                                  absolute="true" />

Kind Regards,

The gTunes Team

Note that the code in Listing 12-34 uses a GSP page directive to set the contentType to text/plain. The default contentType is text/html, so if you want to send HTML mail instead, you can omit this line. And with that, you've implemented e-mail confirmation of registration. However, that's not the end of our e-mail adventures; in the next section, you'll be learning how to send e-mails on a scheduled basis.

Scheduling Jobs

Another frequent use case in web applications is to perform some kind of scheduled execution. Whether it be to produce a monthly report that is too intensive to do via a web interface or to run some periodic system maintenance, scheduling jobs is a problem encountered time and again. In the Java world, the Quartz job scheduling library is one of the most popular open source solutions to this problem. Quartz allows you to schedule jobs that are to be executed on a scheduled basis, such as every 10 minutes or something more specific such as the last Thursday of every month at 1 a.m.

Grails features a plugin for Quartz (http://grails.org/Quartz+Plugin), which integrates Quartz seamlessly into Grails.

Installing the Quartz Plugin

To install the Quartz plugin, you need to run the install-plugin command, as shown in Listing 12-35.

Listitng 12-35. Installing the Quartz Plugin


$ grails install-plugin quartz
...
Plugin provides the following new scripts:
------------------------------------------
grails create-job
grails install-quartz-config

As you can see from the output, the Quartz plugin provides a couple of new commands. The most significant of these is the create-job command, which automates the process of creating a job. As an example, you'll create a job that sends out an automatically generated weekly newsletter detailing the latest new albums in the gTunes store. To get started, run the create-job command as follows:

$ grails create-job com.g2one.gtunes.NewsLetter

You'll end up with a new job class at the location grails-app/jobs/com/g2one/gtunes/NewsLetterJob.groovy. As you can see, the Quartz plugin has introduced an entirely new convention to Grails. All classes that are contained with the grails-app/jobs directory that end with the convention Job and contain an execute method are treated as scheduled jobs!

Simple Jobs

If you open the NewsLetterJob.groovy class, you'll notice it contains a single execute method as well as a timeout property, as shown in Listing 12-36.

Listitng 12-36. The Job Template

class NewsLetterJob {
    def timeout = 1000l // execute job once in 5 seconds
    def execute() {
        // execute task
    }
}

By default, the job is configured to start immediately upon loading and execute every second. The timeout property is specified in milliseconds, so in the preceding example, there will be a 1-second interval between executions. Every second, the job's execute method will be called by the job scheduler. What you do within the execute method is entirely up to you. It could be some system maintenance task or maybe the execution of scheduled reports.

Occasionally, it's useful for a job to start after a set period of time; this is where the startInterval property comes in. Like the timeout property, startInterval accepts a time interval in milliseconds:

def startInterval = 10000

Here the job will execute 10 seconds after the scheduler first loads. The scheduler is, of course, started when a Grails application first loads. Jobs can also be placed in groups and given names using the name and group properties. Listing 12-37 shows how this is done.

Listitng 12-37. Job Naming and Grouping

def name = "newsletter"
def group = "subscriptions"
...

The relevance of this will become more apparent in the section "Interacting with the Scheduler" later in this chapter. For the moment, however, it is time to look at an alternative way to schedule jobs that users of Unix's crontab command will be familiar with.

Cron Jobs

Using the timeout property is useful for simple cases, but what if you want the job to be executed on a set day in the month or week? For use cases such as this, the Quartz plugin allows you to specify a cron expression. If you have a Unix background, you are probably familiar with cron, the time-based scheduling service that got its name from the word chronograph.

A cron expression represents a firing schedule, such as "at 10:30 p.m. every last Sunday of the month," and is represented by six or seven fields representing seconds, minutes, hours, day of the month, month, day of the week, and year (optional), respectively. For example, the cron expression from the English language version would be as follows:

0 30 22 ? * 1L

This may seem a little baffling at first, but there is method to the madness. Table 12-1 should help make things a little clearer.

Table 12-1. Cron Expression Fields

Field Name Allowed Values Allowed Special Characters
Seconds 0–59 , - * /
Minutes 0–59 , - * /
Hours 0–23 , - * /
Day-of-month 1–31 , - * ? / L W C
Month 1–12 or JANDEC , - * /
Day-of-week 1–7 or SUNSAT , - * ? / L C #
Year (optional) Empty, 1970–2099 , - * /

Each field in the cron expression relates to one of the rows in the left column in the order in which it is defined. The second column of allowed values is simple enough, but the special characters (some of which are used in the example expression) might not be so clear:

  • The asterisk (*) character is like a wildcard and means any value is allowed. It appears in the example expression to specify every month.
  • The question mark (?) character is applicable only to the day-of-week and day-of-month fields and cannot be specified by both at the same time. It is used to allow no specific value in either field, equivalent to saying "any day of the week," for example. The example expression indicates there is no specific value for the day-of-month field.
  • You can use commas (,) to specify a group of values. For example, the value SUN, THU, FRI in the day-of-week field translates to "on the days Sunday, Thursday, and Friday."
  • A range of values can be specified using the hyphen (-) character between two values. For example, if you want the job to execute on workdays only, you could put MON-FRI in the day-of-week field.
  • The forward slash (/) character allows increments to be specified in any of the fields. For example, if you have a frequently executed job, you may want to have a value of */15 in the seconds field, which means to execute the job on the seconds 0, 15, 30, and 45.
  • The L character is an interesting one because it generally is shorthand for "last," and if placed in either the day-of-week or day-of-month field on its own, it means the last day of the week or month, respectively. However, this behavior changes if it is included after another character. The example specifies 1L in the day-of-week field, which means "the last Sunday of the month."
  • Next, you have the W character that, when appended to the end of another character, means "the nearest weekday to the given day." For example, using 3W will result in the nearest weekday to the third of the month. If the third is a Sunday, this will be Monday; otherwise, if it's a Saturday, the job will execute on a Friday. In addition, W can be used in combination with L in the form LW to indicate the last weekday of the month.
  • Finally, the # character is used between two numbers as in 5#2, which means "the second Thursday of the month." With this character, it is important to remember that if the second number is out of range, the job will never be executed.

So now that you have learned something about cron expressions, let's see how you go about specifying them in a Grails job, as shown in Listing 12-38.

Listitng 12-38. The Simple Job Is No Longer So Simple

class NewsLetterJob {
      def cronExpression = "0 0 6 * * ?"
      ...
}

Here you have removed the timeout property and provided a cronExpression property that tells the job to execute at 6 a.m. in the morning every day. Again, the remaining configuration is handled for you at runtime. There is plenty more information on Quartz and cron expressions on the Quartz web site that is worth familiarizing yourself with. Table 12-2 presents some examples taken from the Quartz Javadoc of various possible cron expressions and their meanings.

Table 12-2. Example Cron Expressions

Expression Meaning
0 0 12 * * ? Fire at 12 p.m. (noon) every day.
0 15 10 ? * * Fire at 10:15 a.m. every day.
0 15 10 * * ? Fire at 10:15 a.m. every day.
0 15 10 * * ? * Fire at 10:15 a.m. every day.
0 15 10 * * ? 2005 Fire at 10:15 a.m. every day during the year 2005.
0 * 14 * * ? Fire every minute starting at 2 p.m. and ending at 2:59 p.m. every day.
0 0/5 14 * * ? Fire every 5 minutes starting at 2 p.m. and ending at 2:55 p.m. every day.
0 0/5 14,18 * * ? Fire every 5 minutes starting at 2 p.m. and ending at 2:55 p.m., and fire every 5 minutes starting at 6 p.m. and ending at 6:55 p.m. every day.
0 0-5 14 * * ? Fire every minute starting at 2 p.m. and ending at 2:05 p.m. every day.
0 10,44 14 ? 3 WED Fire at 2:10 p.m. and at 2:44 p.m. every Wednesday in the month of March.
0 15 10 ? * MON-FRI Fire at 10:15 a.m. every Monday, Tuesday, Wednesday, Thursday, and Friday.
0 15 10 15 * ? Fire at 10:15 a.m. on the 15th day of every month.
0 15 10 L * ? Fire at 10:15 a.m. on the last day of every month.
0 15 10 ? * 6L Fire at 10:15 a.m. on the last Friday of every month.
0 15 10 ? * 6L 2002-2005 Fire at 10:15 a.m. on every last Friday of every month during the years 2002, 2003, 2004, and 2005.
0 15 10 ? * 6#3 Fire at 10:15 a.m. on the third Friday of every month.

If you recall, we mentioned you could give a job a name or place it in a group. This comes in handy when interacting with the scheduler. More specifically, the scheduler has methods to retrieve existing jobs by name and group.

Interacting with the Scheduler

Quartz and its scheduler control all jobs in Grails. The scheduler itself is an instance of org.quartz.Scheduler, a rich interface for managing jobs that are currently executing and adding new jobs at runtime. The interface is a little too rich to list here, but you can browse through the methods via the Quartz web site:http://www.opensymphony.com/quartz/api/org/quartz/Scheduler.html.

First, though, you need to understand how to obtain a reference to the scheduler. The Spring container once again manages this for you, so obtaining a reference is a simple matter of defining the appropriate property in a controller or service class:

org.quartz.Scheduler quartzScheduler

The property will then be set for you automatically, after which you can start interacting with the scheduler. To start off with, let's take a look at how to obtain existing jobs from the scheduler. The scheduler provides a number of useful methods to achieve this, including those in Listing 12-39.

Listitng 12-39. Methods for Getting Jobs from the Scheduler

class Scheduler {
    ...
    String[] getJobNames();
    String[] getJobGroupNames();
    JobDetail getJobDetail(String jobName, String jobGroupName);
    ...
}

The getJobDetail(jobName, jobGroupName) method will retrieve the org.quartz.JobDetail instance for a specified name and group. The JobDetail describes the job to be executed including information about the class that executes it. Remember that the name and group relate to the name and group properties defined when you create a job. For example, retrieving the NewsLetterJob could be done with the following:

def jobDetail = quartzScheduler.getJobDetail("newsletter","subscriptions")

Scheduling Jobs

Every JobDetail in Quartz when registered with the scheduler is associated with a trigger. A trigger is an instance of the org.quartz.Trigger interface and is responsible for activating the job. For example, once you obtain a reference to a JobDetail, you can register new triggers that fire at certain times, as in Listing 12-40.

Listitng 12-40. Registering New Triggers

def trigger = TriggerUtils.makeDailyTrigger(11, 45)
  trigger.startTime = new Date()
  trigger.name = "myTrigger"
  quartzScheduler.scheduleJob(jobDetail, trigger)

The example in Listing 12-40 introduces another useful class, org.quartz.TriggerUtils, that contains various methods for constructing Trigger instances, one of which is shown in the example. Here you make a new Trigger that will execute the job daily at 11:45 a.m. The Trigger is then registered with the scheduler using the JobDetail instance. Of course, registering a new job is not all that is possible, and in the next few sections you'll see what else can be accomplished with the scheduler.

Pausing and Resuming Jobs

As well as allowing new jobs to be registered, the scheduler also gives you control over existing jobs, including pausing jobs that are currently scheduled. To pause all jobs currently scheduled, you could use the pauseAll method:

quartzScheduler.pauseAll()

Unsurprisingly, there is also a corresponding resumeAll method that will resume all scheduled jobs:

quartzScheduler.resumeAll()

Sometimes, however, it is useful to pause only a single job or group of jobs. This can be achieved with the pauseJob and pauseJobGroup methods:

quartzScheduler.pauseJob("newsletter","subscriptions")
quartzScheduler.pauseJobGroup("subscriptions")

The first statement will pause the newsletter within the subscriptions group, while the second will pause all jobs within the subscriptions group. Note that pausing a job or group of jobs will not stop currently executing jobs from running.

Triggering a Job

If for some reason you need to execute a job immediately and cannot wait for any predefined trigger, the scheduler provides methods to do just this. The aptly named triggerJob method should do the trick nicely:

quartzScheduler.triggerJob("newsletter","subscriptions")

Clearly, cron jobs put a lot of power at your fingertips, and it would be silly not to take advantage of at least some of this power for the gTunes application. In the next section, we'll cover how you can apply what you know so far about jobs to allow users of the gTunes application to receive an e-mail newsletter.

Adding and Removing Jobs

You've already seen one way of scheduling jobs with the scheduleJob method; the addJob method provides a way to add new jobs or replace existing ones. It takes two arguments: a JobDetail instance and a Boolean value that dictates whether it should replace an existing job of the same name and group.

To understand it, you need to explore how to create a JobDetail instance in the first place. At its simplest, the JobDetail class accepts three arguments: the name of the job, the group of the job, and a class that implements the org.quartz.Job interface.

The org.quartz.Job interface has a single method called execute. Therefore, to add a job, you first have to define a class that implements this interface and then register it with the scheduler using a JobDetail bean. However, a much easier alternative is to use Groovy's ability to coerce closures into an instance that implements a single method interface at runtime:

def job = {
    // implement the job here
} as org.quartz.Job

Notice the use of the as keyword to coerce the closure into an instance of the org.quartz.Job interface. Once you have a job, you can then construct a JobDetail instance, and using the addJob method, you can add it to the scheduler:

def jobDetail = new JobDetail("newsletter", "subscriptions", job)
quartzSchedular.addJob(jobDetails,true)

Note that just because you have added a job to the quartzScheduler does not mean it will execute. You have to schedule the job for execution as shown in the "Scheduling Jobs" section. To remove this job later, you can use the deleteJob method:

quartzScheduler.deleteJob("newsletter", "subscriptions")

Jobs in Action

To begin with, to avoid gTunes becoming a spamming machine, you're going to add an option to the registration page so that users can opt into the weekly newsletter. However, before you can do this, you're going to need to create a domain class that models a subscription. You can achieve this using the create-domain-class command:

$ grails create-domain-class com.g2one.gtunes.Subscription

Since there might be different subscription types, the Subscription domain class needs to have a property that defines what type of subscription you're dealing with. A nice way to achieve this if you're running on a Java 1.5 VM is to use a type-safe enum. Listing 12-41 shows the code for the new Subscription class.

Listitng 12-41. Modeling a Subscription

package com.g2one.gtunes

class Subscription {
    SubscriptionType type
    User user

    static mapping = {

        user fetch:"join"

    }

}

enum SubscriptionType {

   NEWSLETTER

}

As you can see from Listing 12-41, you can use the SubscriptionType enum type to specify the type of Subscription a user is a member of. At the moment, there is only a single SubscriptionType, the NEWSLETTER type, but later you'll be adding other types of subscriptions to the gTunes application. Once this is done, you can update the grails-app/views/user/register.gsp view to ask the user whether they want to opt in to receiving the newsletter. Listing 12-42 shows the code added to the register.gsp view.

Listitng 12-42. Adding a Check Box to the register.gsp View

<g:form action="register" name="registerForm">
    ...
    <div class="formField">
        Please tick the following box if you wish to subscribe to
        the weekly gTunes newsletter:
        <g:checkBox name="newsletter"></g:checkBox>
    </div>
    ...
</g:form>

Using the <g:checkBox> tag, you can add a new HTML check box component that will let users choose whether they want to receive the newsletter. Finally, to complete the picture, you can update the register action of the UserController class to create a new Subscription instance when a User registers. Listing 12-43 shows the changes to the register action.

Listitng 12-43. Updating the register Action

def register = {
    ...
    else if(u.save()) {
        session.user = u
        if(params.newsletter) {
            new Subscription(type:SubscriptionType.NEWSLETTER, user:u).save()
        }
        ...
    }
    ...
}

It's time to return to the NewsLetterJob. First, since the job needs to run on the last Thursday of every month, you can use a cron expression to specify an appropriate schedule:

// fire at 7:15am on the last Thursday of every month
def cronExpression = "0 15 7 ? * 5L"

The cronExpression is pretty simple, but remember the L after the 5 for the day of the week! This signifies that it should be the last Thursday of every month instead of every Thursday. With the cronExpression in place, the next thing to consider is how the NewsLetterJob is going to deliver mails. Luckily, you learned about the Mail plugin in the previous section on integrating e-mail. The Mail plugin provides a service that can be injected into the job using dependency injection. Simply add the following property to the NewsLetterJob class definition:

def mailService

Now it's time to put the Subscription class to action within the execute method of the NewsLetterJob. First you need to look up all the subscribed e-mail addresses. You can do this with a single criteria query, as shown in Listing 12-44.

Listitng 12-44. Obtaining Subscribed E-mails

def emails = Subscription.withCriteria {
    projections {
        user {
            property 'email'
        }
    }
    eq('type', SubscriptionType.NEWSLETTER)
                     }

Listing 12-44 is using GORM's withCriteria method to obtain a list of e-mail addresses that the mail needs to be sent out to. By using the projections method within the withCriteria method to specify that you want the email property of all the user properties within the Subscription class, you can load only the data you need. With a bunch of e-mail addresses in hand, the next thing to do is grab a list of the newest 10 albums from the last week. This can be achieved with a simple dynamic finder, as shown in Listing 12-45.

Listitng 12-45. Obtains the Newest 10 Albums from the Last Week

def now = new Date()
def albumList =
        Album.findAllByDateCreatedBetween(now-7,
                                          now,
                                          [sort:'dateCreated',
                                          max:10,
                                          order:'desc'] )

Groovy overrides the minus operator on java.util.Date so that when you subtract a number from a date, Groovy will go back in time the equivalent number of days. The result is that the expression now-7 gives you a date from a week ago. The expression findAllByDateCreatedBetween will let you find all the Album instances for a given date range. With that done, it's now a simple matter of sending an e-mail to each user. Listing 12-46 shows the code that uses the mailService instance to fire off an e-mail to each e-mail address.

Listitng 12-46. Sending E-mails with the mailService

def month = new GregorianCalendar().get(Calendar.MONTH)
for(email in emails) {
   mailService.sendMail {
        from "[email protected]"
        to email
        title "The gTunes Monthly News Letter - $month"
        body view:"/emails/newsletter",
             model:[latestAlbums:albumList,
                    month:month]
   }
}

As you can see from the example in Listing 12-46, you can use regular Java APIs to get the current month and then simply get the mailService to deliver the mails. Once again, the code uses the view arguments of the body method to specify a view to render for the mail at the location grails-app/views/emails/newsletter.gsp. Listing 12-47 shows the full code listing for the NewsLetterJob.

Listitng 12-47. The NewsLetterJob Code

package com.g2one.gtunes
class NewsLetterJob {
    // fire at 7:15am on the last Thursday of every month
    def cronExpression = "0 15 7 ? * 5L"

    def mailService
    def execute() {
        def emails = Subscription.withCriteria {
            projections {
                user {
                    property 'email'
                }
             }
             eq('type', SubscriptionType.NEWSLETTER)
         }

         def now = new Date()
def albumList =
     Album.findAllByDateCreatedBetween(now-7,
                                       now,
                                       [sort:'dateCreated',
                                       max:10,
                                       order:'desc'])
if(albumList) {
    def month = new GregorianCalendar().get(Calendar.MONTH)
    for(email in emails) {
        mailService.sendMail {
            from "[email protected]"
            to email
            title "The gTunes Monthly News Letter - $month"
            body view:"/emails/newsletter",
                 model:[latestAlbums:albumList,
                        month:month]
          }
       }
     }
   }
}

To wrap things up, you can add a view that renders the newsletter. Listing 12-48 shows an example newsletter.gsp view that uses HTML mail to deliver the e-mail.

Listitng 12-48. The newsletter.gsp View

<html>
    <head>
    </head><
     body id="newsletter">
        <h1>The gTunes Month Newsletter for ${month}</h1>
        <p>Welcome to the gTunes monthly newsletter!
            Below are the latest releases
            available at <g:createLink controller="store"
                                  absolute="true" />
        </p>
        <h2>Latest Album Releases</h2>
        <g:each var="album" in="${latestAlbums}">
            <div class="albumArt">
                <b>Title</b>: <g:link controller="album"
                                 action="show"
                                 id="${album.id}">${album.title}</g:link>
                    <br>
<b>Artist</b>: ${album.artist.name} <br>
                <div class="albumArt">
                    <music:albumArt album="${album.title}"
                                   artist="${album.artist.name}">
                </div>
           </div>
       </g:each>
   </body>
</html>

Well, that is it for jobs—for the time being, at least. Another thing to remember is that although Grails gives you the convenience of defining jobs by convention, the full power of Quartz and all its features are there for you to take advantage of. All in all, this makes for a pretty powerful and easy-to-use combination! Before you get too excited, however, let's take a look at a less glamorous task when integrating Grails: deployment.

Deployment

Moving your application from a development environment onto a production or test server often presents you with a number of choices. The options when deploying Grails are many and varied, and they run the gamut from simple to complex. In the following sections, you'll be looking at different ways of deploying Grails and how to customize the deployment process.

Deploying with Grails

If you're looking for a simple way to manage deployment and aren't too concerned about fine-tuning the details of your container, then deploying with Grails itself is certainly a simple way to go about it. To deploy with Grails, all you need to do is install Grails on the target server and then use the run-war command from the root of the project:

$ grails run-war

This will start a Jetty server on port 8080. On this point, you can configure the ubiquitous Apache HTTPD server (http://httpd.apache.org/) to use mod_proxy to relay requests to the Jetty server. The details of this are covered on the Jetty web site at http://docs.codehaus.org/display/JETTY/Configuring+mod_proxy. Alternatively, you could even run Jetty on port 80 so that it acts as the primary web server:

$ grails -Dserver.port=80 run-war

However, as simple as this approach is, many organizations favor a more structured approach to deployment using that standard Java stalwart, the WAR file.

Deploying to a Container

You learned about creating a WAR file as early as Chapter 2. When thinking about deployment in the Java world, the first thing that usually comes to mind is how to create a WAR. It is one of the strengths of the Java platform that you can take a WAR file and deploy it onto such a wide range of containers.

From the commercial 800-pound gorillas like IBM WebSphere and BEA WebLogic to the popular open source containers like Tomcat and JBoss, there are options aplenty. Against the background of all this helpful standardization, it is unfortunate that the way in which you deploy a WAR file is still not standardized.

On something like Tomcat, it's typically just a matter of dropping your WAR file into the TOMCAT_HOME/webapps directory, while on WebSphere there is a fancy GUI wizard that allows you to upload a WAR file via a browser. Nevertheless, there are some important things to consider when deploying to a container. The following is a list of key points to remember when deploying with Grails:

  • Make sure that the -server flag is passed to the JVM that runs your container to enable the server VM. Running Grails on the client VM has a negative impact on performance.
  • Depending on the number of GSP views you have, you may need to allocate more permgen space (the area of memory the JVM uses for dynamically compiled classes). GSP views are compiled at runtime on first load into byte code, so they require permgen space. You can allocate more permgen with the -XX:MaxPermSize=256m flag.
  • It is advisable to allocate extra memory to the JVM when running a Grails application. Simple Grails applications have been known to perform well on shared virtual hosting with low memory, but the more you can allocate, the better. For example, to allocate 512MB of heap space, you can use the -Xmx512M flag.

Application Versioning and Metadata

You may have already noticed by now that when you run the grails war command, the generated WAR file has a version number on the end of the file name. You may be wondering where this mysterious version number comes from. Basically, when you create a Grails application, the version number of the application is set to 0.1 in the application's metadata.

You can change the version number by calling the set-version command, as shown in Listing 12-49.

Listitng 12-49. Setting the Application Version Number

grails set-version 0.2

Then when you build a new WAR, the version number from Listing 12-49 will be used instead. At runtime you can inspect the application metadata using the grailsApplication object:

println grailsApplication.metadata."app.version"

or using the <g:meta> tag from a GSP, as shown in Listing 12-50.

Listitng 12-50. Using Application Metadata

Version <g:meta name="app.version"/>
Built with Grails <g:meta name="app.grails.version"/>

Customizing the WAR

If you want to customize the way in which the WAR file is produced, you can consider taking advantage of a number of hooks. For example, say you wanted to provide a different base web.xml template in order to include your own custom servlets; you can do so with the grails.config. base.webXml setting in grails-app/conf/Config.groovy:
grails.config.base.webXml="file:${userHome}/.settings/my-web.xml"

Also, if you need to change the location where the WAR file is generated, you can do so using the grails.war.destFile property:

grails.war.destFile = "${tomcatHome}/webapps"

In terms of modifying the contents of the WAR, by default Grails will take everything from the web-app directory and include it in the WAR. If you prefer this not to happen, you can override this process with your own custom step using the grails.war.copyToWebApp setting:

grails.war.copyToWebApp = {
    fileset(dir:"/usr/var/mywar")
}

Alternatively, if you simply want to include additional resources in the WAR, you can do so with the grails.war.resources setting, as shown in Listing 12-51.

Listitng 12-51. Using the grails.war.resources Setting to Include Custom Resources

grails.war.resources = { stagingDir ->
    // include static resources
    copy(dir:stagingDir) {
        fileset(dir:"/usr/var/www/htdocs")
    }
}

Notice how the closure assigned to grails.war.resources gets passed an argument that is the location of the directory where the WAR is being built. You can then use custom copy steps to include whatever extra resources you need. Once you actually have a WAR, you may want to perform some initial population of the database state when the application loads. We'll be covering how to do this in the next section.

Populating the Database with BootStrap Classes

Whenever an application loads for the first time, there may be some initial state that needs to be in place for the application to operate in a correct manner. One way to do this is with BootStrap classes. If you look at the grails-app/conf directory, you may have noticed a class called BootStrap.groovy. Listing 12-52 shows the template for this class.

Listitng 12-52. A BootStrap Class

class BootStrap{
     def init = { servletContext ->
     }
     def destroy = {
     }
}

As you can see, there is an init method that is called when the container first loads and a destroy method. The destroy method is called on container shutdown, although it should be noted that it is not guaranteed to be invoked and hence shouldn't be relied upon for anything critical.

Within the Bootstrap class, you can use GORM to populate the database. Thanks to GORM's usage of fluent APIs,10 it is pretty easy to create an object graph, as shown in Listing 12-53.

Listitng 12-53. Populating Data on Application Load

def init = {
    def album = new Album(title:"Because of the Times")
                     .addToSongs(title:"Knocked Up")
                     .addToSongs(title:"Charmer")
   ...
   new Artist(name:"Kings of Leon")
               .addToAlbums(album)
               .save(flush:true)
}

If you need to populate per-environment data, then you can use the GrailsUtil class to obtain the environment and perform a switch. Listing 12-54 shows an example of this.

Listitng 12-54. Per-Environment Bootstrapping

def init = {
     switch(grails.util.GrailsUtil.environment) {
         case "development":
           // initialize in development here
           break
            case "production":
            // initialize in production here
            break
       }
}

Summary

Integrating Grails is a broad topic, as you have seen by the number of topics covered in this chapter. These range from integration with command-line tools to your development environment to the servers you finally deploy onto. Many options are available to you—so many in fact that an entire book on the subject wouldn't be inappropriate. The good news is that many of the deployment options and techniques that you use in the Java space are equally applicable to Grails.

Whether it be Java EE–compliant containers like Tomcat or your favorite build tool, there is typically a way to get Groovy and Grails to work seamlessly in your environment. In the next chapter, you'll learn about a whole new subject that is critical to the workings of Grails— the plugin system. Throughout the book you've been a user of many of Grails' more prominent plugins. In this chapter alone, you explored using the Mail and Quartz plugins.

Now it's time for you to turn into a plugin creator and learn how you can modularize your application through the use of plugins.



10. A fluent API is often referred to as method chaining because it involves writing methods that return objects in a manner so multiple methods can be chained in a sequence. See http://www.martinfowler.com/bliki/FluentInterface.html for a more complete definition.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset