HHH-8577 - ClearListener: allow to listen for clear events

This commit is contained in:
Steve Ebersole 2013-10-07 16:29:10 -05:00
parent 3d366a526e
commit b20ac395cb
6 changed files with 259 additions and 75 deletions

View File

@ -55,6 +55,7 @@ import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventType;
import static org.hibernate.event.spi.EventType.AUTO_FLUSH;
import static org.hibernate.event.spi.EventType.CLEAR;
import static org.hibernate.event.spi.EventType.DELETE;
import static org.hibernate.event.spi.EventType.DIRTY_CHECK;
import static org.hibernate.event.spi.EventType.EVICT;
@ -226,6 +227,11 @@ public class EventListenerRegistryImpl implements EventListenerRegistry {
workMap
);
prepareListeners(
CLEAR,
workMap
);
// flush listeners
prepareListeners(
FLUSH,

View File

@ -0,0 +1,40 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.event.spi;
/**
* An event for {@link org.hibernate.Session#clear()} listening
*
* @author Steve Ebersole
*/
public class ClearEvent extends AbstractEvent {
/**
* Constructs an event from the given event session.
*
* @param source The session event source.
*/
public ClearEvent(EventSource source) {
super( source );
}
}

View File

@ -0,0 +1,40 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.event.spi;
import java.io.Serializable;
/**
* Listener for notification of {@link org.hibernate.Session#clear()}
*
* @author Steve Ebersole
*/
public interface ClearEventListener extends Serializable {
/**
* Callback for {@link org.hibernate.Session#clear()} notification
*
* @param event The event representing the clear
*/
public void onClear(ClearEvent event);
}

View File

@ -38,90 +38,61 @@ import org.hibernate.HibernateException;
* @author Steve Ebersole
*/
public class EventType<T> {
public static final EventType<LoadEventListener> LOAD
= new EventType<LoadEventListener>( "load", LoadEventListener.class );
public static final EventType<ResolveNaturalIdEventListener> RESOLVE_NATURAL_ID
= new EventType<ResolveNaturalIdEventListener>( "resolve-natural-id", ResolveNaturalIdEventListener.class );
public static final EventType<InitializeCollectionEventListener> INIT_COLLECTION
= new EventType<InitializeCollectionEventListener>( "load-collection", InitializeCollectionEventListener.class );
public static final EventType<LoadEventListener> LOAD = create( "load", LoadEventListener.class );
public static final EventType<ResolveNaturalIdEventListener> RESOLVE_NATURAL_ID = create( "resolve-natural-id", ResolveNaturalIdEventListener.class );
public static final EventType<SaveOrUpdateEventListener> SAVE_UPDATE
= new EventType<SaveOrUpdateEventListener>( "save-update", SaveOrUpdateEventListener.class );
public static final EventType<SaveOrUpdateEventListener> UPDATE
= new EventType<SaveOrUpdateEventListener>( "update", SaveOrUpdateEventListener.class );
public static final EventType<SaveOrUpdateEventListener> SAVE
= new EventType<SaveOrUpdateEventListener>( "save", SaveOrUpdateEventListener.class );
public static final EventType<PersistEventListener> PERSIST
= new EventType<PersistEventListener>( "create", PersistEventListener.class );
public static final EventType<PersistEventListener> PERSIST_ONFLUSH
= new EventType<PersistEventListener>( "create-onflush", PersistEventListener.class );
public static final EventType<InitializeCollectionEventListener> INIT_COLLECTION = create( "load-collection", InitializeCollectionEventListener.class );
public static final EventType<MergeEventListener> MERGE
= new EventType<MergeEventListener>( "merge", MergeEventListener.class );
public static final EventType<SaveOrUpdateEventListener> SAVE_UPDATE = create( "save-update", SaveOrUpdateEventListener.class );
public static final EventType<SaveOrUpdateEventListener> UPDATE = create( "update", SaveOrUpdateEventListener.class );
public static final EventType<SaveOrUpdateEventListener> SAVE = create( "save", SaveOrUpdateEventListener.class );
public static final EventType<PersistEventListener> PERSIST = create( "create", PersistEventListener.class );
public static final EventType<PersistEventListener> PERSIST_ONFLUSH = create( "create-onflush", PersistEventListener.class );
public static final EventType<DeleteEventListener> DELETE
= new EventType<DeleteEventListener>( "delete", DeleteEventListener.class );
public static final EventType<MergeEventListener> MERGE = create( "merge", MergeEventListener.class );
public static final EventType<ReplicateEventListener> REPLICATE
= new EventType<ReplicateEventListener>( "replicate", ReplicateEventListener.class );
public static final EventType<DeleteEventListener> DELETE = create( "delete", DeleteEventListener.class );
public static final EventType<FlushEventListener> FLUSH
= new EventType<FlushEventListener>( "flush", FlushEventListener.class );
public static final EventType<AutoFlushEventListener> AUTO_FLUSH
= new EventType<AutoFlushEventListener>( "auto-flush", AutoFlushEventListener.class );
public static final EventType<DirtyCheckEventListener> DIRTY_CHECK
= new EventType<DirtyCheckEventListener>( "dirty-check", DirtyCheckEventListener.class );
public static final EventType<FlushEntityEventListener> FLUSH_ENTITY
= new EventType<FlushEntityEventListener>( "flush-entity", FlushEntityEventListener.class );
public static final EventType<ReplicateEventListener> REPLICATE = create( "replicate", ReplicateEventListener.class );
public static final EventType<EvictEventListener> EVICT
= new EventType<EvictEventListener>( "evict", EvictEventListener.class );
public static final EventType<FlushEventListener> FLUSH = create( "flush", FlushEventListener.class );
public static final EventType<AutoFlushEventListener> AUTO_FLUSH = create( "auto-flush", AutoFlushEventListener.class );
public static final EventType<DirtyCheckEventListener> DIRTY_CHECK = create( "dirty-check", DirtyCheckEventListener.class );
public static final EventType<FlushEntityEventListener> FLUSH_ENTITY = create( "flush-entity", FlushEntityEventListener.class );
public static final EventType<LockEventListener> LOCK
= new EventType<LockEventListener>( "lock", LockEventListener.class );
public static final EventType<ClearEventListener> CLEAR = create( "clear", ClearEventListener.class );
public static final EventType<EvictEventListener> EVICT = create( "evict", EvictEventListener.class );
public static final EventType<RefreshEventListener> REFRESH
= new EventType<RefreshEventListener>( "refresh", RefreshEventListener.class );
public static final EventType<LockEventListener> LOCK = create( "lock", LockEventListener.class );
public static final EventType<PreLoadEventListener> PRE_LOAD
= new EventType<PreLoadEventListener>( "pre-load", PreLoadEventListener.class );
public static final EventType<PreDeleteEventListener> PRE_DELETE
= new EventType<PreDeleteEventListener>( "pre-delete", PreDeleteEventListener.class );
public static final EventType<PreUpdateEventListener> PRE_UPDATE
= new EventType<PreUpdateEventListener>( "pre-update", PreUpdateEventListener.class );
public static final EventType<PreInsertEventListener> PRE_INSERT
= new EventType<PreInsertEventListener>( "pre-insert", PreInsertEventListener.class );
public static final EventType<RefreshEventListener> REFRESH = create( "refresh", RefreshEventListener.class );
public static final EventType<PostLoadEventListener> POST_LOAD
= new EventType<PostLoadEventListener>( "post-load", PostLoadEventListener.class );
public static final EventType<PostDeleteEventListener> POST_DELETE
= new EventType<PostDeleteEventListener>( "post-delete", PostDeleteEventListener.class );
public static final EventType<PostUpdateEventListener> POST_UPDATE
= new EventType<PostUpdateEventListener>( "post-update", PostUpdateEventListener.class );
public static final EventType<PostInsertEventListener> POST_INSERT
= new EventType<PostInsertEventListener>( "post-insert", PostInsertEventListener.class );
public static final EventType<PreLoadEventListener> PRE_LOAD = create( "pre-load", PreLoadEventListener.class );
public static final EventType<PreDeleteEventListener> PRE_DELETE = create( "pre-delete", PreDeleteEventListener.class );
public static final EventType<PreUpdateEventListener> PRE_UPDATE = create( "pre-update", PreUpdateEventListener.class );
public static final EventType<PreInsertEventListener> PRE_INSERT = create( "pre-insert", PreInsertEventListener.class );
public static final EventType<PostDeleteEventListener> POST_COMMIT_DELETE
= new EventType<PostDeleteEventListener>( "post-commit-delete", PostDeleteEventListener.class );
public static final EventType<PostUpdateEventListener> POST_COMMIT_UPDATE
= new EventType<PostUpdateEventListener>( "post-commit-update", PostUpdateEventListener.class );
public static final EventType<PostInsertEventListener> POST_COMMIT_INSERT
= new EventType<PostInsertEventListener>( "post-commit-insert", PostInsertEventListener.class );
public static final EventType<PostLoadEventListener> POST_LOAD = create( "post-load", PostLoadEventListener.class );
public static final EventType<PostDeleteEventListener> POST_DELETE = create( "post-delete", PostDeleteEventListener.class );
public static final EventType<PostUpdateEventListener> POST_UPDATE = create( "post-update", PostUpdateEventListener.class );
public static final EventType<PostInsertEventListener> POST_INSERT = create( "post-insert", PostInsertEventListener.class );
public static final EventType<PreCollectionRecreateEventListener> PRE_COLLECTION_RECREATE
= new EventType<PreCollectionRecreateEventListener>( "pre-collection-recreate", PreCollectionRecreateEventListener.class );
public static final EventType<PreCollectionRemoveEventListener> PRE_COLLECTION_REMOVE
= new EventType<PreCollectionRemoveEventListener>( "pre-collection-remove", PreCollectionRemoveEventListener.class );
public static final EventType<PreCollectionUpdateEventListener> PRE_COLLECTION_UPDATE
= new EventType<PreCollectionUpdateEventListener>( "pre-collection-update", PreCollectionUpdateEventListener.class );
public static final EventType<PostDeleteEventListener> POST_COMMIT_DELETE = create( "post-commit-delete", PostDeleteEventListener.class );
public static final EventType<PostUpdateEventListener> POST_COMMIT_UPDATE = create( "post-commit-update", PostUpdateEventListener.class );
public static final EventType<PostInsertEventListener> POST_COMMIT_INSERT = create( "post-commit-insert", PostInsertEventListener.class );
public static final EventType<PostCollectionRecreateEventListener> POST_COLLECTION_RECREATE
= new EventType<PostCollectionRecreateEventListener>( "post-collection-recreate", PostCollectionRecreateEventListener.class );
public static final EventType<PostCollectionRemoveEventListener> POST_COLLECTION_REMOVE
= new EventType<PostCollectionRemoveEventListener>( "post-collection-remove", PostCollectionRemoveEventListener.class );
public static final EventType<PostCollectionUpdateEventListener> POST_COLLECTION_UPDATE
= new EventType<PostCollectionUpdateEventListener>( "post-collection-update", PostCollectionUpdateEventListener.class );
public static final EventType<PreCollectionRecreateEventListener> PRE_COLLECTION_RECREATE = create( "pre-collection-recreate", PreCollectionRecreateEventListener.class );
public static final EventType<PreCollectionRemoveEventListener> PRE_COLLECTION_REMOVE = create( "pre-collection-remove", PreCollectionRemoveEventListener.class );
public static final EventType<PreCollectionUpdateEventListener> PRE_COLLECTION_UPDATE = create( "pre-collection-update", PreCollectionUpdateEventListener.class );
public static final EventType<PostCollectionRecreateEventListener> POST_COLLECTION_RECREATE = create( "post-collection-recreate", PostCollectionRecreateEventListener.class );
public static final EventType<PostCollectionRemoveEventListener> POST_COLLECTION_REMOVE = create( "post-collection-remove", PostCollectionRemoveEventListener.class );
public static final EventType<PostCollectionUpdateEventListener> POST_COLLECTION_UPDATE = create( "post-collection-update", PostCollectionUpdateEventListener.class );
private static <T> EventType<T> create(String name, Class<T> listenerClass) {
return new EventType<T>( name, listenerClass );
}
/**
* Maintain a map of {@link EventType} instances keyed by name for lookup by name as well as {@link #values()}
@ -132,14 +103,13 @@ public class EventType<T> {
@Override
public Map<String, EventType> run() {
final Map<String, EventType> typeByNameMap = new HashMap<String, EventType>();
final Field[] fields = EventType.class.getDeclaredFields();
for ( int i = 0, max = fields.length; i < max; i++ ) {
if ( EventType.class.isAssignableFrom( fields[i].getType() ) ) {
for ( Field field : EventType.class.getDeclaredFields() ) {
if ( EventType.class.isAssignableFrom( field.getType() ) ) {
try {
final EventType typeField = ( EventType ) fields[i].get( null );
final EventType typeField = (EventType) field.get( null );
typeByNameMap.put( typeField.eventName(), typeField );
}
catch( Exception t ) {
catch (Exception t) {
throw new HibernateException( "Unable to initialize EventType map", t );
}
}

View File

@ -109,6 +109,8 @@ import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.AutoFlushEvent;
import org.hibernate.event.spi.AutoFlushEventListener;
import org.hibernate.event.spi.ClearEvent;
import org.hibernate.event.spi.ClearEventListener;
import org.hibernate.event.spi.DeleteEvent;
import org.hibernate.event.spi.DeleteEventListener;
import org.hibernate.event.spi.DirtyCheckEvent;
@ -332,6 +334,11 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
private void internalClear() {
persistenceContext.clear();
actionQueue.clear();
final ClearEvent event = new ClearEvent( this );
for ( ClearEventListener listener : listeners( EventType.CLEAR ) ) {
listener.onClear( event );
}
}
public long getTimestamp() {

View File

@ -0,0 +1,121 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.events;
import org.hibernate.Session;
import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.ClearEvent;
import org.hibernate.event.spi.ClearEventListener;
import org.hibernate.event.spi.EventType;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.metamodel.source.MetadataImplementor;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
import org.junit.Test;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertEquals;
/**
* @author Steve Ebersole
*/
public class ClearEventListenerTest extends BaseCoreFunctionalTestCase {
@Test
public void testExplicitClear() {
listener.callCount = 0;
Session s = openSession();
s.clear();
assertEquals( 1, listener.callCount );
s.close();
assertEquals( 1, listener.callCount );
}
@Test
public void testAutoClear() {
listener.callCount = 0;
Session s = openSession();
( (SessionImplementor) s ).setAutoClear( true );
s.beginTransaction();
assertEquals( 0, listener.callCount );
s.getTransaction().commit();
assertEquals( 1, listener.callCount );
s.close();
assertEquals( 1, listener.callCount );
}
private TheListener listener = new TheListener();
private static class TheListener implements ClearEventListener {
private int callCount;
@Override
public void onClear(ClearEvent event) {
callCount++;
}
}
@Override
protected void prepareBootstrapRegistryBuilder(BootstrapServiceRegistryBuilder builder) {
super.prepareBootstrapRegistryBuilder( builder );
builder.with(
new Integrator() {
@Override
public void integrate(
Configuration configuration,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
integrate(serviceRegistry);
}
@Override
public void integrate( MetadataImplementor metadata,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry ) {
integrate(serviceRegistry);
}
private void integrate( SessionFactoryServiceRegistry serviceRegistry ) {
serviceRegistry.getService( EventListenerRegistry.class ).setListeners(
EventType.CLEAR,
listener
);
}
@Override
public void disintegrate(
SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
}
}
);
}
}