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