Tuesday, 26 August 2008

Using Liquibase DropAll Automagically

If you're using the grails liquibase plugin you might find it useful to have it run on application startup (e.g. when the war file is deployed) rather than using the grails command line target (i.e. grails migrate). One way to achieve this is to add an entry for the liquibase spring bean in your resources.groovy like so:

liquibase(SpringLiquibase) {
dataSource = dataSource
changeLog = "classpath:migrations/changelog.xml"
executeEnabled = true

For certain environments (continuous build etc.) it may also be useful to have liquibase clear out the database and build the schema from scratch. The main Liquibase class has a dropAll() method that looks like it'll do the trick (there's also a 'grails drop-all' command), so let's create a spring bean that'll run before the liquibase migration kicks in (it'd be a bit pointless to blow away the database after you've just created it). The spring
'depends-on' attribute should work nicely here but it would appear that grails' BeanBuilder does not support attributes (foiled again). We can, however, implement BeanFactoryPostProcessor to achieve the desired effect:

import java.sql.Connection
import liquibase.spring.SpringLiquibase
import org.springframework.beans.factory.config.BeanDefinition
import org.springframework.beans.factory.config.BeanFactoryPostProcessor
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory

class LiquibaseDropAll extends SpringLiquibase implements BeanFactoryPostProcessor {

String runBefore = 'liquibase'

void afterPropertiesSet() {
Connection conn = null
conn = getDataSource().getConnection()

//make liquibase bean depend upon this bean so that dropAll runs before migration
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(runBefore)
beanDefinition.setAttribute('depends-on', beanName)

The last thing to do is add this bean to your resources.groovy, most probably with a conditional based on environment:

def config = org.codehaus.groovy.grails.commons.ConfigurationHolder.config
if(config.dataSource.liquibase.dropAll) {
liquibaseDropAll(LiquibaseDropAll) {
dataSource = dataSource

Now just add something like:

dataSource {
liquibase.dropAll = true

to the environments you want to liquify and you're away.

1 comment:

SteveC said...