Permalink
Browse files

Moved to Hibernate based listener to preserve previous state onUpdate

  • Loading branch information...
1 parent 4def57f commit a7471e9a4611bd414b7276f37527a42fa227723c Michael J Salera committed Dec 4, 2012
@@ -1,12 +1,13 @@
class BatesGrailsPlugin {
// the plugin version
- def version = "0.20"
+ def version = "0.23"
// the version or versions of Grails the plugin is designed for
def grailsVersion = "2.0 > *"
// the other plugins this plugin depends on
- def dependsOn = [mongodbMorphia: "0.8.2"]
+ def dependsOn = [mongodbMorphia: "0.8.2",
+ hibernate: "2.1.1"]
// executor: "0.3"]
// resources that are excluded from plugin packaging
@@ -58,19 +59,28 @@ build an Admin style front end to view and filter thru all log documents, for ex
// TODO Implement additions to web.xml (optional), this event occurs before
}
- def doWithSpring = {
- businessAuditLogService(com.freerangeconsultants.plugins.bates.core.BusinessAuditLogService)
- }
+def doWithSpring = {
+ businessAuditLogService(com.freerangeconsultants.plugins.bates.core.BusinessAuditLogService)
+
+ auditListener(com.freerangeconsultants.plugins.bates.listeners.BusinessAuditLogListener)
+ hibernateEventListeners(org.codehaus.groovy.grails.orm.hibernate.HibernateEventListeners) {
+ listenerMap = ['post-insert': auditListener,
+ 'pre-update': auditListener,
+ 'pre-delete': auditListener]
+ }
+}
def doWithDynamicMethods = { ctx ->
// TODO Implement registering dynamic methods to classes (optional)
}
+/*
def doWithApplicationContext = { applicationContext ->
application.mainContext.eventTriggeringInterceptor.datastores.each { k, datastore ->
applicationContext.addApplicationListener(new com.freerangeconsultants.plugins.bates.listeners.BusinessAuditLogListener(datastore))
}
}
+*/
def onChange = { event ->
// TODO Implement code that is executed when any artefact that this plugin is
@@ -1,5 +1,6 @@
#Grails Metadata file
-#Sun Dec 02 18:43:39 PST 2012
+#Mon Dec 03 22:54:39 PST 2012
app.grails.version=2.1.1
app.name=bates
+plugins.hibernate=2.1.1
plugins.mongodb-morphia=0.8.2
@@ -2,7 +2,6 @@ package com.freerangeconsultants.plugins.bates.core
import com.freerangeconsultants.plugins.bates.domain.AuditLogEvent
-
/**
* Log audit events from any persistence object to MongoDB sharded cluster
*
@@ -19,7 +18,7 @@ class BusinessAuditLogService {
/**
* Use this method to return a list of the History of the given object id
*
- * @param clazz Class object for example of the Invoice.class
+ * @param clazz Class object
* @param persistedObjectId id of the object caller is looking for
* @return
*/
@@ -42,10 +41,11 @@ class BusinessAuditLogService {
*/
def recordLogEvent(String eventType, String className, persistedObjectId, oldeState, newState) {
//magic of the dataStore
- def auditEvent = new AuditLogEvent(eventName: eventType.toString(), className: className, persistedObjectId: persistedObjectId as String)
+ def auditEvent = new AuditLogEvent(eventName: eventType, className: className, persistedObjectId: persistedObjectId as String)
if (oldeState) { auditEvent.oldState = oldeState }
if (newState) { auditEvent.newState = newState }
auditEvent.save(flush: true)
+ println( "${eventType} for class ${className} Id -> ${persistedObjectId}" )
print('.')
true
}
View
Binary file not shown.
View
@@ -1,4 +1,4 @@
-<plugin name='bates' version='0.20' grailsVersion='2.0 &gt; *'>
+<plugin name='bates' version='0.23' grailsVersion='2.0 &gt; *'>
<author>Michael Salera</author>
<authorEmail>mikesalera@mac.com</authorEmail>
<title>Business Audit Trail Events System (BATES) Plugin</title>
@@ -33,6 +33,7 @@ build an Admin style front end to view and filter thru all log documents, for ex
<plugins />
<runtimePluginRequirements>
<plugin name='mongodbMorphia' version='0.8.2' />
+ <plugin name='hibernate' version='2.1.1' />
</runtimePluginRequirements>
<behavior />
</plugin>
@@ -1,23 +1,19 @@
package com.freerangeconsultants.plugins.bates.listeners
+import com.freerangeconsultants.plugins.bates.core.BusinessAuditLogService
import grails.util.GrailsUtil
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory
import org.codehaus.groovy.grails.commons.ApplicationHolder
import org.codehaus.groovy.grails.commons.GrailsApplication
-import org.grails.datastore.mapping.core.Datastore
-import org.grails.datastore.mapping.engine.EntityAccess;
-import org.grails.datastore.mapping.engine.event.*;
-import org.grails.datastore.mapping.engine.event.AbstractPersistenceEvent
-import org.grails.datastore.mapping.engine.event.AbstractPersistenceEventListener
-import org.grails.datastore.mapping.model.PersistentEntity;
-
+import org.hibernate.HibernateException
+import org.hibernate.cfg.Configuration
+import org.hibernate.collection.PersistentList
+import org.hibernate.collection.PersistentSet
+import org.hibernate.event.*
+import org.springframework.beans.factory.NoSuchBeanDefinitionException
import org.springframework.context.ApplicationContext
-import org.springframework.context.ApplicationEvent
-
-import com.freerangeconsultants.plugins.bates.core.BusinessAuditLogService
-
/**
* As of Grails 2.0 there is a new API for plugins and applications to register and listen for persistence events.
@@ -29,84 +25,99 @@ import com.freerangeconsultants.plugins.bates.core.BusinessAuditLogService
* @author Mike Salera
* @version 1.0
*/
-class BusinessAuditLogListener extends AbstractPersistenceEventListener {
-
-// BusinessAuditLogService businessAuditLogService
- Log LOG = LogFactory.getLog(BusinessAuditLogListener.class)
+//class BusinessAuditLogListener extends AbstractPersistenceEventListener {
- public BusinessAuditLogListener(final Datastore dataStore) {
- super(dataStore)
- println this.class.name
- println "Running on: " + dataStore.class.name
+/**
+ * Or you could use the low-level Hibernate Events...
+ * Complete list of listeners/events can be obtained at <tt>org.hibernate.event.EventListeners</tt>.
+ *
+ * @see org.hibernate.event.EventListeners
+ * @author Mike Salera, Shawn Hartsock
+ *
+ */
+class BusinessAuditLogListener
+ implements PostInsertEventListener, PreUpdateEventListener, PreDeleteEventListener, Initializable {
+
+ def Log LOG = LogFactory.getLog(BusinessAuditLogListener.class)
+
+ /**
+ * Log insertions made to the current model in the Audit Trail.
+ * new objects
+ *
+ * @param event
+ */
+ @Override
+ public void onPostInsert(PostInsertEvent event) {
+ handleEvent('onPostInsert', event)
+ }
- }
+ /**
+ * Log updates made to the current model in the Audit Trail.
+ * Return true if the operation should be vetoed
+ * @param event
+ */
+ @Override
+ public boolean onPreUpdate(PreUpdateEvent event) {
+ handleEvent('onPreUpdate', event)
+ return false
+ }
- @Override
- public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
- return true
- }
+ /**
+ * Log deletions made to the current model in the the Audit Trail.
+ * Return true if the operation should be vetoed
+ * @param event
+ */
+ @Override
+ public boolean onPreDelete(PreDeleteEvent event) {
+ handleEvent('onPreDelete', event)
+ return false
+ }
-@Override
-protected void onPersistenceEvent(AbstractPersistenceEvent event) {
- handleEvent(event)
-}
+ def handleEvent(String eventName, event) {
+ LOG.info("handleEvent: ${eventName}")
- def handleEvent(AbstractPersistenceEvent event) {
- def businessAuditLogService = ContextUtils.getBeanFromApplicationContext("businessAuditLogService")
+ def businessAuditLogService = ContextUtils.getBeanFromApplicationContext("businessAuditLogService")
def String className = null
def Object persistedObjectId = null
def oldState = null // for UPDATES
def newState = null
- // gotta have entity or entityName
- if (!event?.entityObject) { return false }
-
//skip if test mode
- if (!GrailsUtil.getEnvironment().equals(GrailsApplication.ENV_TEST)) {
- className = event?.entityObject?.class.name ?: 'Category'
- persistedObjectId = event?.entityObject?.id?.toString() ?: 1
-
- switch(event.eventType) {
- case EventType.PostInsert:
- println ''
- println this.class.name + " Got a Persistence event!"
- println "POST INSERT ${event.entityObject}"
-// newState = getStateMap(event?.persister?.propertyNames, event?.getState())
- businessAuditLogService.recordLogEvent('insert', className, persistedObjectId, null, newState)
+ if (!GrailsUtil.getEnvironment().equals(GrailsApplication.ENV_TEST) && isAuditableEntity(event?.entity)) {
+ className = event?.entity?.class.name
+ persistedObjectId = event?.entity?.id?.toString()
- break
-
- case EventType.PreUpdate:
- println ''
- println this.class.name + " Got a Persistence event!"
- println "PRE UPDATE ${event.entityObject}"
-// oldState = getStateMap(event?.persister?.propertyNames, event?.getOldState())
-// newState = getStateMap(event?.persister?.propertyNames, event?.getState())
+ if (eventName == 'onPostInsert') {
+ newState = getStateMap(event?.persister?.propertyNames, event?.getState())
+ businessAuditLogService.recordLogEvent('insert', className, persistedObjectId, null, newState)
+ }
+ else if (eventName == 'onPreUpdate') {
+ oldState = getStateMap(event?.persister?.propertyNames, event?.getOldState())
+ newState = getStateMap(event?.persister?.propertyNames, event?.getState())
businessAuditLogService.recordLogEvent('update', className, persistedObjectId, oldState, newState)
- break;
-
- case EventType.PreDelete:
- println ''
- println this.class.name + " Got a Persistence event!"
- println "PRE DELETE ${event.entityObject}"
-// oldState = getStateMap(event?.persister?.propertyNames, event?.getDeletedState())
+ }
+ else if (eventName == 'onPreDelete') {
+ oldState = getStateMap(event?.persister?.propertyNames, event?.getDeletedState())
businessAuditLogService.recordLogEvent('delete', className, persistedObjectId, oldState, null)
- break
-
- default:
- log.warn("Cannot support event: ${event.eventType}")
+ }
+ else {
+ throw new IllegalArgumentException("Cannot support event: ${eventName}")
}
}
}
-
- Boolean isAuditableEntity(entity) {
- entity?.metaClass.hasProperty(entity, 'auditable') && entity.auditable == Boolean.TRUE
+ @Override
+ public void initialize(Configuration cfg) {
+ LOG.info("initializing")
}
+ def Boolean isAuditableEntity(entity) {
+ entity?.metaClass.hasProperty(entity, 'auditable') && entity?.auditable == Boolean.TRUE
+ }
+
private def getStateMap(String[] names, Object[] state) {
def map = [:]
for (int i = 0; i < names.length; i++) {
@@ -117,33 +128,32 @@ protected void onPersistenceEvent(AbstractPersistenceEvent event) {
sanitizeMap(map)
}
-
// propertyNames may have null values on the above call to put
//create Map with no missing teeth
private def sanitizeMap(aMap) {
def entriesToBeRemoved = []
aMap?.each { key, value ->
- if (key && value) {
+ if (value != null && !(value instanceof PersistentSet) && !(value instanceof PersistentList)) {
aMap[key] = value?.toString()
}
else { entriesToBeRemoved << key }
}
entriesToBeRemoved.each { key -> aMap.remove(key) }
return aMap
}
-
}
+
class ContextUtils {
def static getBeanFromApplicationContext(String beanName){
- ApplicationContext ctx = (ApplicationContext)ApplicationHolder.getApplication().getMainContext()
- def bean
+ ApplicationContext ctx = ApplicationHolder.getApplication().getMainContext() as ApplicationContext
+
+ def bean = null
try{
bean = ctx.getBean(beanName)
- } catch (org.springframework.beans.factory.NoSuchBeanDefinitionException ex){
- //do nothing. this just means the requested bean doesn't exist and the method will return null
+ } catch (NoSuchBeanDefinitionException ex){
}
return bean
}
-}
+}

0 comments on commit a7471e9

Please sign in to comment.