1. Loading your application context
This is an obvious first step, and this is what Grails expects you to do:
includeTargets << grailsScript("_GrailsBootstrap") target(main: "My Gant script") { depends(configureProxy, packageApp, classpath, loadApp, configureApp, compile) ... } setDefaultTarget("main")
Yep, all these parts of depends() clause are needed, although "compile" part is needed only if domain objects are directly used, i.e., MyDomainClass.findByAttr().
2. Setting target environment
Two ways to do that. Standard grails way:
grails prod my-script - for environments pre-defined in Grails, such as 'dev' or 'prod'
grails -Dgrails.env=stage my-script - for custom environments
or place this at the beginning of your script:
scriptEnv = "envName"
and then simply run
grails my-script
3. Accessing your application classes and calling methods on them
The following example shows how to call a service method in your Gant script.
def serviceClass = grailsApp.getClassForName("com.killerapp.AwesomeService") def serviceClassMethod = serviceClass.metaClass.getMetaMethod("blazingMethod") def service = appCtx.getBean("awesomeService") serviceClassMethod.invoke(service, [arg1, arg2] as Object[])
As seen in the example, there are 2 implicit variables that the script provides: "grailsApp" and "appCtx". First one is an instance of org.codehaus.groovy.grails.commons.GrailsApplication, and the second one is an instance of org.springframework.context.ApplicationContext. To call a service method, both are needed: grailsApp helps retrieve an instance of MetaMethod wrapper of the method you want to call. However, MetaMethod has to be called on a specific instance, which is Spring context singleton that Grails application creates when it initializes. appCtx helps retrieve that singleton.
However, this is not enough. Your service method has to be defined as an actual method, like this:
void blazingMethod(arg1, arg2) { ... }, NOT a closure:
def blazingMethod { arg1, arg2 -> ... }
That is because groovy closures are compiled into non-anonymous inner classes, not regular Java methods. Therefore, accessing closures by name will not work.
4. Running queries
To run dynamic finders, nothing extra needs to be done:
MyDomainClass.findByName("someName")
To run updates, an instance of org.springframework.orm.hibernate3.HibernateTemplate is needed. It can be obtained using appCtx:
def sessionFactory = appCtx.getBean("sessionFactory") def template = new HibernateTemplate(sessionFactory) def newRecord = new MyDomainClass(name: "someName") template.saveOrUpdate(newRecord)
HibernateTemplate can also be used for queries, like this:
def domainClass = grailsApp.getClassForName("com.killerapp.MyDomainClass") def allRecords = template.loadAll(domainClass)
5. Cleaning script cache
As of Grails 1.3.4, using depends(compile) with accessing domain classes in a Gant script generates the following error simply running a script once, then making a change and re-running it:
java.lang.NoClassDefFoundError: com.killerapp.MyDomainClass
This is because scriptCache needs to be cleaned. Simply delete ~/.grails/1.3.4/projects/killerApp/scriptCache/ directory, and rerun the script.