Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
GRAILS-5725 applied patch to allow Hibernate event listeners
  • Loading branch information
burtbeckwith committed Jul 31, 2010
1 parent 0c06068 commit 657bad4
Show file tree
Hide file tree
Showing 5 changed files with 202 additions and 7 deletions.
Expand Up @@ -17,6 +17,7 @@
import groovy.lang.GroovySystem;
import groovy.lang.MetaClassRegistry;

import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

Expand All @@ -25,12 +26,14 @@
import org.codehaus.groovy.grails.commons.GrailsApplication;
import org.codehaus.groovy.grails.orm.hibernate.cfg.DefaultGrailsDomainConfiguration;
import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsDomainConfiguration;
import org.codehaus.groovy.grails.orm.hibernate.events.SaveOrUpdateEventListener;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.cache.CacheException;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.event.*;
import org.hibernate.metadata.ClassMetadata;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
Expand All @@ -53,6 +56,7 @@ public class ConfigurableLocalSessionFactoryBean extends
private GrailsApplication grailsApplication;
private Class<?> configClass;
private Class<?> currentSessionContextClass;
private HibernateEventListeners hibernateEventListeners;

/**
* Sets class to be used for the Hibernate CurrentSessionContext
Expand Down Expand Up @@ -149,10 +153,6 @@ private boolean isCacheConfigurationError(Throwable cause) {
return cause != null && (cause instanceof CacheException);
}

public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// not used
}

@Override
public void destroy() throws HibernateException {
MetaClassRegistry registry = GroovySystem.getMetaClassRegistry();
Expand All @@ -164,5 +164,112 @@ public void destroy() throws HibernateException {
}
super.destroy();
}
}

/**
* Merge HibernateEventListeners with the default ones
*/
@Override
protected void postProcessConfiguration(final Configuration config) throws HibernateException {
super.postProcessConfiguration(config);
if (hibernateEventListeners == null || hibernateEventListeners.getListenerMap() == null) {
return;
}

EventListeners listeners = config.getEventListeners();
Map<String,Object> listenerMap = hibernateEventListeners.getListenerMap();
addNewListenerToConfiguration(config, "auto-flush", AutoFlushEventListener.class,
listeners.getAutoFlushEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "merge", MergeEventListener.class,
listeners.getMergeEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "create", PersistEventListener.class,
listeners.getPersistEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "create-onflush", PersistEventListener.class,
listeners.getPersistOnFlushEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "delete", DeleteEventListener.class,
listeners.getDeleteEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "dirty-check", DirtyCheckEventListener.class,
listeners.getDirtyCheckEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "evict", EvictEventListener.class,
listeners.getEvictEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "flush", FlushEventListener.class,
listeners.getFlushEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "flush-entity", FlushEntityEventListener.class,
listeners.getFlushEntityEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "load", LoadEventListener.class,
listeners.getLoadEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "load-collection", InitializeCollectionEventListener.class,
listeners.getInitializeCollectionEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "lock", LockEventListener.class,
listeners.getLockEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "refresh", RefreshEventListener.class,
listeners.getRefreshEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "replicate", ReplicateEventListener.class,
listeners.getReplicateEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "save-update", SaveOrUpdateEventListener.class,
listeners.getSaveOrUpdateEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "save", SaveOrUpdateEventListener.class,
listeners.getSaveEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "update", SaveOrUpdateEventListener.class,
listeners.getUpdateEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "pre-load", PreLoadEventListener.class,
listeners.getPreLoadEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "pre-update", PreUpdateEventListener.class,
listeners.getPreUpdateEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "pre-delete", PreDeleteEventListener.class,
listeners.getPreDeleteEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "pre-insert", PreInsertEventListener.class,
listeners.getPreInsertEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "pre-collection-recreate", PreCollectionRecreateEventListener.class,
listeners.getPreCollectionRecreateEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "pre-collection-remove", PreCollectionRemoveEventListener.class,
listeners.getPreCollectionRemoveEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "pre-collection-update", PreCollectionUpdateEventListener.class,
listeners.getPreCollectionUpdateEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "post-load", PostLoadEventListener.class,
listeners.getPostLoadEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "post-update", PostUpdateEventListener.class,
listeners.getPostUpdateEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "post-delete", PostDeleteEventListener.class,
listeners.getPostDeleteEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "post-insert", PostInsertEventListener.class,
listeners.getPostInsertEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "post-commit-update", PostUpdateEventListener.class,
listeners.getPostCommitUpdateEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "post-commit-delete", PostDeleteEventListener.class,
listeners.getPostCommitDeleteEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "post-commit-insert", PostInsertEventListener.class,
listeners.getPostCommitInsertEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "post-collection-recreate", PostCollectionRecreateEventListener.class,
listeners.getPostCollectionRecreateEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "post-collection-remove", PostCollectionRemoveEventListener.class,
listeners.getPostCollectionRemoveEventListeners(), listenerMap);
addNewListenerToConfiguration(config, "post-collection-update", PostCollectionUpdateEventListener.class,
listeners.getPostCollectionUpdateEventListeners(), listenerMap);
}

@SuppressWarnings("unchecked")
private <T> void addNewListenerToConfiguration(final Configuration config, final String listenerType,
final Class<? extends T> klass, final T[] currentListeners, final Map<String,Object> newlistenerMap) {

Object newListener = newlistenerMap.get(listenerType);
if (newListener == null) return;

if (currentListeners != null && currentListeners.length > 0) {
T[] newListeners = (T[])Array.newInstance(klass, currentListeners.length + 1);
System.arraycopy(currentListeners, 0, newListeners, 0, currentListeners.length);
newListeners[currentListeners.length] = (T)newListener;
config.setListeners(listenerType, newListeners);
}
else {
config.setListener(listenerType, newListener);
}
}

public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// not used
}

public void setHibernateEventListeners(final HibernateEventListeners listeners) {
hibernateEventListeners = listeners;
}
}
@@ -0,0 +1,30 @@
/* Copyright 2004-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.groovy.grails.orm.hibernate;

import java.util.Map;

public class HibernateEventListeners {

private Map<String, Object> listenerMap;

public Map<String, Object> getListenerMap() {
return listenerMap;
}

public void setListenerMap(Map<String, Object> listenerMap) {
this.listenerMap = listenerMap;
}
}
Expand Up @@ -36,6 +36,7 @@ import org.codehaus.groovy.grails.commons.spring.RuntimeSpringConfiguration
import org.codehaus.groovy.grails.exceptions.GrailsDomainException
import org.codehaus.groovy.grails.orm.hibernate.ConfigurableLocalSessionFactoryBean
import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTransactionManager
import org.codehaus.groovy.grails.orm.hibernate.HibernateEventListeners
import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsDomainBinder
import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil
import org.codehaus.groovy.grails.orm.hibernate.cfg.HibernateNamedQueriesBuilder
Expand Down Expand Up @@ -185,6 +186,7 @@ Using Grails' default naming strategy: '${GrailsDomainBinder.namingStrategy.getC
}
proxyHandler(HibernateProxyHandler)
eventTriggeringInterceptor(ClosureEventTriggeringInterceptor)
hibernateEventListeners(HibernateEventListeners)
entityInterceptor(EmptyInterceptor)
sessionFactory(ConfigurableLocalSessionFactoryBean) {
dataSource = dataSource
Expand Down Expand Up @@ -219,6 +221,7 @@ Using Grails' default naming strategy: '${GrailsDomainBinder.namingStrategy.getC
'post-update':eventTriggeringInterceptor,
'pre-delete':eventTriggeringInterceptor,
'post-delete':eventTriggeringInterceptor]
hibernateEventListeners = hibernateEventListeners
}

transactionManager(GrailsHibernateTransactionManager) {
Expand Down
Expand Up @@ -111,8 +111,7 @@ hibernate {
ctx.registerMockBean("messageSource", new StaticMessageSource())

def springConfig = new WebRuntimeSpringConfiguration(ctx, gcl)
dependentPlugins*.doWithRuntimeConfiguration(springConfig)
dependentPlugins.each { mockManager.registerMockPlugin(it); it.manager = mockManager }
doWithRuntimeConfiguration dependentPlugins, springConfig

appCtx = springConfig.getApplicationContext()
applicationContext = appCtx
Expand All @@ -129,6 +128,11 @@ hibernate {
}
}

protected void doWithRuntimeConfiguration(dependentPlugins, springConfig) {
dependentPlugins*.doWithRuntimeConfiguration(springConfig)
dependentPlugins.each { mockManager.registerMockPlugin(it); it.manager = mockManager }
}

protected void tearDown() {

if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
Expand Down
@@ -0,0 +1,51 @@
package org.codehaus.groovy.grails.orm.hibernate

import org.hibernate.event.PostDeleteEvent
import org.hibernate.event.PostDeleteEventListener
import org.hibernate.event.PostInsertEvent
import org.hibernate.event.PostInsertEventListener

import org.codehaus.groovy.grails.commons.test.AbstractGrailsMockTests
import org.codehaus.groovy.grails.plugins.DefaultGrailsPlugin

/**
* @author Burt Beckwith
*/
class HibernateEventListenerTests extends AbstractGrailsHibernateTests {

private plugin

protected void afterPluginInitialization() {
plugin = new DefaultGrailsPlugin(EventListenerGrailsPlugin, ga)
mockManager.registerMockPlugin plugin
plugin.manager = mockManager
}

protected void doWithRuntimeConfiguration(dependentPlugins, springConfig) {
super.doWithRuntimeConfiguration dependentPlugins, springConfig
plugin.doWithRuntimeConfiguration springConfig
}

void testDoRuntimeConfiguration() {
def eventListeners = appCtx.sessionFactory.eventListeners
assertTrue eventListeners.postInsertEventListeners.any { it instanceof TestAuditListener }
assertTrue eventListeners.postDeleteEventListeners.any { it instanceof TestAuditListener }
assertFalse eventListeners.postUpdateEventListeners.any { it instanceof TestAuditListener }
}
}

class EventListenerGrailsPlugin {
def version = 1
def doWithSpring = {
testAuditListener(TestAuditListener)
hibernateEventListeners(HibernateEventListeners) {
listenerMap = ['post-insert': testAuditListener,
'post-delete': testAuditListener]
}
}
}

class TestAuditListener implements PostInsertEventListener, PostDeleteEventListener {
void onPostInsert(PostInsertEvent event) {}
void onPostDelete(PostDeleteEvent event) {}
}

0 comments on commit 657bad4

Please sign in to comment.