Grails scripting

Grails, programming

Within any Web application, there is the Web site, which is pretty well served by Grails.  Very soon, there will inevitably be some background processing that needs to be done for the holistic system.  These background tasks are typically:

  • background in nature such that typical users won’t know of their existence
  • process-intensive with little or no interactive flows
  • console stdin/stdout for scripting
  • independent of the Web app’s life cycle / process space

With respect to Grails, the Web app has GORM and all its convenient properties abstracted in very concise domain classes.  However, these are only available to the Grails run-time.  There are posts (this and the like) that talks about having multiple Grails apps sharing the domain objects, but that doesn’t fit the profiles listed above since I’d have two interactive Web apps, albeit one for public and one for admin/internal controllers and services.

An alternative is to look at Grails scripting, of which there are two flavors that I know of:

  • Grails scripts
  • Custom Groovy scripts

Both of these seem to be able to get at the Spring ApplicationContext and transitively all its beans.

Grails scripts (create-script)

Create these using:

grails create-script MyScript

A script template will be added under the /scripts subdir (e.g. /scripts/MyScript.groovy):

includeTargets << grailsScript("_GrailsBootstrap")

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

}

setDefaultTarget(main)

Within the body of target(...) { }, we can add a list of dependencies and then use “appCtx” to refer to the Spring ApplicationContext:

target(...) {
    depends(configureProxy, packageApp, classpath, loadApp, configureApp, compile)

    def myService = appCtx.myService
    println(myService.doSomething())
}

Note the use of appCtx to reference the Spring ApplicationContext.

The script can be moved to these places also:

  • $GRAILS_HOME/scripts
  • $USER_HOME/.grails/scripts
  • $PROJECT_HOME/plugins/*/scripts

To run it:

cd $PROJECT_HOME
grails MyScript

Note the conciseness of the command.

Custom Groovy scripts (run-scripts)

This approach allows writing less coupled Groovy scripts that can be placed anywhere on the file system (not confined under the project’s /scripts subdir, for instance).

The price to pay for that flexibility are:

  • The working directory when I run the script still must be where the Grails project is
  • Getting the reference to the ApplicationContext is quite convoluted a process

So I can create a script at ~/scripts/grails/myapp/MyService.groovy:

def appCtx = new User().domainClass.grailsApplication.mainContext
def myService = appCtx.myService

println(myService.doSomething())

Note how I got the appCtx instance: creating a bean (must be properly imported or qualified) class, then walk the reference to the domainClass and then grailsApplication and then mainContext.

To run it:

cd $PROJECT_HOME
grails run-script ~/scripts/grails/myapp/MyScript.groovy

Note the use of the run-script target and the full path to the script file. Since the script file can be anywhere, there can certainly be many versions of the script file.

Similarities and Differences

Both types of scripts have full access to GORM and Spring.

Scripts created by “grails create-script”:

can only reside in one of four locations

  • $GRAILS_HOME/scripts
  • $USER_HOME/.grails/scripts
  • $PROJECT_HOME/scripts
  • $PROJECT_HOME/plugins/*/scripts

can be invoked simply via “grails <script name>” (the .groovy suffix is not required)

can reuse some of the _Grails* scripts that came with Grails (e.g. _GrailsBootstrap)

does NOT have access to $PROJECT_HOME/src/groovy or $PROJECT_HOME/src/java during run-time

Scripts run by “grails run-script”:

can reside outside $PROJECT_HOME.  However, when running, the working subdirectory needs to be $PROJECT_HOME

requires full path to *.groovy file when run using “grails run-script <full path to script file>.groovy”

HAS access to $PROJECT_HOME/src/groovy or $PROJECT_HOME/src/java during run-time

Reference

Page on create-script from Grails

Page on run-script from Grails