Showing posts with label gorm-event-listener. Show all posts
Showing posts with label gorm-event-listener. Show all posts

Wednesday, October 18, 2017

Hooking into GORM events | Hooking into GORM custom event listener from plugin in Grails | Grails Custom Gorm Event Listener

Hooking into GORM events | Hooking into GORM custom event listener from plugin in Grails | Grails Custom Gorm Event Listener

At first configure your datasource.groovy to connect with your desired database as below:


dataSource {
    pooled = true
    jmxExport = true
    driverClassName = "org.h2.Driver"
    username = "sa"
    password = ""
}
hibernate {
    cache.use_second_level_cache = true
    cache.use_query_cache = true
    cache.region.factory_class = 'net.sf.ehcache.hibernate.EhCacheRegionFactory'
    cache.provider_class = 'net.sf.ehcache.hibernate.EhCacheProvider'
    format_sql = false
    use_sql_comments = false
}

// environment specific settings
environments {
    development {
        dataSource {
            pooled = true
            url = "jdbc:mysql://localhost/my_db?useUnicode=yes&characterEncoding=UTF-8"
            driverClassName = "com.mysql.jdbc.Driver"
            username = "root"
            password = ""
            dialect = "org.hibernate.dialect.MySQL5InnoDBDialect"
            dbCreate = "update"
            properties {
                jmxEnabled = true
                initialSize = 5
                maxActive = 50
                minIdle = 5
                maxIdle = 25
                maxWait = 10000
                maxAge = 10 * 60000
                timeBetweenEvictionRunsMillis = 5000
                minEvictableIdleTimeMillis = 60000
                validationQuery = "SELECT 1"
                validationQueryTimeout = 3
                validationInterval = 15000
                testOnBorrow = true
                testWhileIdle = true
                testOnReturn = false
                jdbcInterceptors = "ConnectionState"
                defaultTransactionIsolation = java.sql.Connection.TRANSACTION_READ_COMMITTED
            }
            logSql = true
            loggingSql = true
        }
    }
    test {
        dataSource {
            
        }
    }
    production {
        dataSource {
            
        }
    }
}


Now add "runtime 'mysql:mysql-connector-java:5.1.29'" to your BiuldConfig.groovy file under "dependencies" section if you used MySQL.
Now create controller like below:

package com.custom_gorm_event_listener

class HomeController {
    def index() {
        println("Tracking-post-load-function")
        println(Home.list())
        println("")
        println("")
        println("Tracking-post-update-function")
        Home.last().departmentName = "Department-${System.currentTimeMillis()}".toString()
        render ""
    }
}

And as well as a Domain class as below:

package com.custom_gorm_event_listener

class Home {
    Long id
    String name
    String roll
    String departmentName

    static constraints = {
        departmentName nullable: true
    }
}

This is the most important step, need to create and gorm event listener class as below:

package com.custom_gorm_event_listener

import grails.util.Holders
import org.codehaus.groovy.grails.orm.hibernate.EventTriggeringInterceptor
import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore
import org.grails.datastore.mapping.core.Datastore
import org.grails.datastore.mapping.engine.event.AbstractPersistenceEvent
import org.grails.datastore.mapping.engine.event.ValidationEvent
import org.hibernate.HibernateException
import org.hibernate.event.spi.AbstractPreDatabaseOperationEvent
import org.hibernate.event.spi.PostDeleteEvent
import org.hibernate.event.spi.PostInsertEvent
import org.hibernate.event.spi.PostLoadEvent
import org.hibernate.event.spi.PostUpdateEvent
import org.hibernate.event.spi.PreDeleteEvent
import org.hibernate.event.spi.PreInsertEvent
import org.hibernate.event.spi.PreLoadEvent
import org.hibernate.event.spi.PreUpdateEvent
import org.hibernate.event.spi.SaveOrUpdateEvent

/**
 * Created by pritom on 18/10/2017.
 */
class GormEventListener extends EventTriggeringInterceptor {
    GormEventListener() {
        this((HibernateDatastore) Holders.applicationContext.getBean(Datastore), new ConfigObject())
    }

    GormEventListener(HibernateDatastore datastore, ConfigObject co) {
        super(datastore, co)
    }

    protected void onPersistenceEvent(AbstractPersistenceEvent event) {
        super.onPersistenceEvent(event)
    }

    private void updateState(AbstractPreDatabaseOperationEvent event) {
        Object[] newState = event.persister.getPropertyValuesToInsert(event.entity, null, event.session)
        Object[] oldState = event.state
        newState.eachWithIndex { m, i ->
            oldState[i] = m
        }
    }

    boolean onPreInsert(PreInsertEvent event) {
        updateState(event)
        return false
    }

    void onPostInsert(PostInsertEvent event) {
        println("onPostInsert::${event.entity}")
    }

    boolean onPreUpdate(PreUpdateEvent event) {
        updateState(event)
        return false
    }

    void onPostUpdate(PostUpdateEvent event) {
        println("onPostUpdate::${event.entity}")
    }

    boolean onPreDelete(PreDeleteEvent event) {
        return false
    }

    void onPostDelete(PostDeleteEvent event) {
        println("onPostDelete::${event.entity}")
    }

    void onPreLoad(PreLoadEvent event) {

    }

    void onPostLoad(PostLoadEvent event) {
        println("onPostLoad::${event.entity}")
    }

    void onSaveOrUpdate(SaveOrUpdateEvent event) throws HibernateException {
        println("onSaveOrUpdate::${event.entity}")
    }

    void onValidate(ValidationEvent event) {

    }
}

And finally need to hook our custom gorm event listener to gorm event, to do so we have to add some functionalities to BootStrap.groovy as below:

import com.custom_gorm_event_listener.GormEventListener
import org.codehaus.groovy.grails.commons.GrailsApplication
import org.springframework.context.event.AbstractApplicationEventMulticaster
import org.springframework.context.support.AbstractApplicationContext

class BootStrap {
    GrailsApplication grailsApplication

    def init = { servletContext ->
        addGormListener()
    }

    def destroy = {

    }

    void addGormListener() {
        AbstractApplicationContext context = grailsApplication.mainContext
        AbstractApplicationEventMulticaster multicaster = context.applicationEventMulticaster
        List listeners = multicaster.applicationListeners
        multicaster.removeAllListeners()
        /* Placing our listener at first */
        multicaster.addApplicationListener(new GormEventListener())
        listeners.each {
            multicaster.addApplicationListener(it)
        }
    }
}

We are finished, if we run our project we can track when an instance create, update or read through our listener:

Tracking-post-load-function
Hibernate: select this_.id as id1_0_0_, this_.version as version2_0_0_, this_.department_name as departme3_0_0_, this_.name as name4_0_0_, this_.roll as roll5_0_0_ from home this_
onPostLoad::com.custom_gorm_event_listener.Home : 53
onPostLoad::com.custom_gorm_event_listener.Home : 54
onPostLoad::com.custom_gorm_event_listener.Home : 55
[com.custom_gorm_event_listener.Home : 53, com.custom_gorm_event_listener.Home : 54, com.custom_gorm_event_listener.Home : 55]


Tracking-post-update-function
Hibernate: select this_.id as id1_0_0_, this_.version as version2_0_0_, this_.department_name as departme3_0_0_, this_.name as name4_0_0_, this_.roll as roll5_0_0_ from home this_ order by this_.id desc limit ?
Hibernate: update home set version=?, department_name=?, name=?, roll=? where id=? and version=?
onPostUpdate::com.custom_gorm_event_listener.Home : 55