From b20ac395cb8c2a0c94acc4a559f570c63950f346 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Mon, 7 Oct 2013 16:29:10 -0500 Subject: [PATCH] HHH-8577 - ClearListener: allow to listen for clear events --- .../internal/EventListenerRegistryImpl.java | 6 + .../org/hibernate/event/spi/ClearEvent.java | 40 ++++++ .../event/spi/ClearEventListener.java | 40 ++++++ .../org/hibernate/event/spi/EventType.java | 120 +++++++---------- .../org/hibernate/internal/SessionImpl.java | 7 + .../test/events/ClearEventListenerTest.java | 121 ++++++++++++++++++ 6 files changed, 259 insertions(+), 75 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/event/spi/ClearEvent.java create mode 100644 hibernate-core/src/main/java/org/hibernate/event/spi/ClearEventListener.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/events/ClearEventListenerTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/event/service/internal/EventListenerRegistryImpl.java b/hibernate-core/src/main/java/org/hibernate/event/service/internal/EventListenerRegistryImpl.java index c5dfc19dcd..8f97f1dfcc 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/service/internal/EventListenerRegistryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/event/service/internal/EventListenerRegistryImpl.java @@ -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, diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/ClearEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/ClearEvent.java new file mode 100644 index 0000000000..27c97c8f41 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/event/spi/ClearEvent.java @@ -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 ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/ClearEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/spi/ClearEventListener.java new file mode 100644 index 0000000000..050de37e75 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/event/spi/ClearEventListener.java @@ -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); +} diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/EventType.java b/hibernate-core/src/main/java/org/hibernate/event/spi/EventType.java index aa63f0cc3b..13f25db8a0 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/spi/EventType.java +++ b/hibernate-core/src/main/java/org/hibernate/event/spi/EventType.java @@ -38,90 +38,61 @@ import org.hibernate.HibernateException; * @author Steve Ebersole */ public class EventType { - public static final EventType LOAD - = new EventType( "load", LoadEventListener.class ); - public static final EventType RESOLVE_NATURAL_ID - = new EventType( "resolve-natural-id", ResolveNaturalIdEventListener.class ); - public static final EventType INIT_COLLECTION - = new EventType( "load-collection", InitializeCollectionEventListener.class ); + public static final EventType LOAD = create( "load", LoadEventListener.class ); + public static final EventType RESOLVE_NATURAL_ID = create( "resolve-natural-id", ResolveNaturalIdEventListener.class ); - public static final EventType SAVE_UPDATE - = new EventType( "save-update", SaveOrUpdateEventListener.class ); - public static final EventType UPDATE - = new EventType( "update", SaveOrUpdateEventListener.class ); - public static final EventType SAVE - = new EventType( "save", SaveOrUpdateEventListener.class ); - public static final EventType PERSIST - = new EventType( "create", PersistEventListener.class ); - public static final EventType PERSIST_ONFLUSH - = new EventType( "create-onflush", PersistEventListener.class ); + public static final EventType INIT_COLLECTION = create( "load-collection", InitializeCollectionEventListener.class ); - public static final EventType MERGE - = new EventType( "merge", MergeEventListener.class ); + public static final EventType SAVE_UPDATE = create( "save-update", SaveOrUpdateEventListener.class ); + public static final EventType UPDATE = create( "update", SaveOrUpdateEventListener.class ); + public static final EventType SAVE = create( "save", SaveOrUpdateEventListener.class ); + public static final EventType PERSIST = create( "create", PersistEventListener.class ); + public static final EventType PERSIST_ONFLUSH = create( "create-onflush", PersistEventListener.class ); - public static final EventType DELETE - = new EventType( "delete", DeleteEventListener.class ); + public static final EventType MERGE = create( "merge", MergeEventListener.class ); - public static final EventType REPLICATE - = new EventType( "replicate", ReplicateEventListener.class ); + public static final EventType DELETE = create( "delete", DeleteEventListener.class ); - public static final EventType FLUSH - = new EventType( "flush", FlushEventListener.class ); - public static final EventType AUTO_FLUSH - = new EventType( "auto-flush", AutoFlushEventListener.class ); - public static final EventType DIRTY_CHECK - = new EventType( "dirty-check", DirtyCheckEventListener.class ); - public static final EventType FLUSH_ENTITY - = new EventType( "flush-entity", FlushEntityEventListener.class ); + public static final EventType REPLICATE = create( "replicate", ReplicateEventListener.class ); - public static final EventType EVICT - = new EventType( "evict", EvictEventListener.class ); + public static final EventType FLUSH = create( "flush", FlushEventListener.class ); + public static final EventType AUTO_FLUSH = create( "auto-flush", AutoFlushEventListener.class ); + public static final EventType DIRTY_CHECK = create( "dirty-check", DirtyCheckEventListener.class ); + public static final EventType FLUSH_ENTITY = create( "flush-entity", FlushEntityEventListener.class ); - public static final EventType LOCK - = new EventType( "lock", LockEventListener.class ); + public static final EventType CLEAR = create( "clear", ClearEventListener.class ); + public static final EventType EVICT = create( "evict", EvictEventListener.class ); - public static final EventType REFRESH - = new EventType( "refresh", RefreshEventListener.class ); + public static final EventType LOCK = create( "lock", LockEventListener.class ); - public static final EventType PRE_LOAD - = new EventType( "pre-load", PreLoadEventListener.class ); - public static final EventType PRE_DELETE - = new EventType( "pre-delete", PreDeleteEventListener.class ); - public static final EventType PRE_UPDATE - = new EventType( "pre-update", PreUpdateEventListener.class ); - public static final EventType PRE_INSERT - = new EventType( "pre-insert", PreInsertEventListener.class ); + public static final EventType REFRESH = create( "refresh", RefreshEventListener.class ); - public static final EventType POST_LOAD - = new EventType( "post-load", PostLoadEventListener.class ); - public static final EventType POST_DELETE - = new EventType( "post-delete", PostDeleteEventListener.class ); - public static final EventType POST_UPDATE - = new EventType( "post-update", PostUpdateEventListener.class ); - public static final EventType POST_INSERT - = new EventType( "post-insert", PostInsertEventListener.class ); + public static final EventType PRE_LOAD = create( "pre-load", PreLoadEventListener.class ); + public static final EventType PRE_DELETE = create( "pre-delete", PreDeleteEventListener.class ); + public static final EventType PRE_UPDATE = create( "pre-update", PreUpdateEventListener.class ); + public static final EventType PRE_INSERT = create( "pre-insert", PreInsertEventListener.class ); - public static final EventType POST_COMMIT_DELETE - = new EventType( "post-commit-delete", PostDeleteEventListener.class ); - public static final EventType POST_COMMIT_UPDATE - = new EventType( "post-commit-update", PostUpdateEventListener.class ); - public static final EventType POST_COMMIT_INSERT - = new EventType( "post-commit-insert", PostInsertEventListener.class ); + public static final EventType POST_LOAD = create( "post-load", PostLoadEventListener.class ); + public static final EventType POST_DELETE = create( "post-delete", PostDeleteEventListener.class ); + public static final EventType POST_UPDATE = create( "post-update", PostUpdateEventListener.class ); + public static final EventType POST_INSERT = create( "post-insert", PostInsertEventListener.class ); - public static final EventType PRE_COLLECTION_RECREATE - = new EventType( "pre-collection-recreate", PreCollectionRecreateEventListener.class ); - public static final EventType PRE_COLLECTION_REMOVE - = new EventType( "pre-collection-remove", PreCollectionRemoveEventListener.class ); - public static final EventType PRE_COLLECTION_UPDATE - = new EventType( "pre-collection-update", PreCollectionUpdateEventListener.class ); + public static final EventType POST_COMMIT_DELETE = create( "post-commit-delete", PostDeleteEventListener.class ); + public static final EventType POST_COMMIT_UPDATE = create( "post-commit-update", PostUpdateEventListener.class ); + public static final EventType POST_COMMIT_INSERT = create( "post-commit-insert", PostInsertEventListener.class ); - public static final EventType POST_COLLECTION_RECREATE - = new EventType( "post-collection-recreate", PostCollectionRecreateEventListener.class ); - public static final EventType POST_COLLECTION_REMOVE - = new EventType( "post-collection-remove", PostCollectionRemoveEventListener.class ); - public static final EventType POST_COLLECTION_UPDATE - = new EventType( "post-collection-update", PostCollectionUpdateEventListener.class ); + public static final EventType PRE_COLLECTION_RECREATE = create( "pre-collection-recreate", PreCollectionRecreateEventListener.class ); + public static final EventType PRE_COLLECTION_REMOVE = create( "pre-collection-remove", PreCollectionRemoveEventListener.class ); + public static final EventType PRE_COLLECTION_UPDATE = create( "pre-collection-update", PreCollectionUpdateEventListener.class ); + public static final EventType POST_COLLECTION_RECREATE = create( "post-collection-recreate", PostCollectionRecreateEventListener.class ); + public static final EventType POST_COLLECTION_REMOVE = create( "post-collection-remove", PostCollectionRemoveEventListener.class ); + public static final EventType POST_COLLECTION_UPDATE = create( "post-collection-update", PostCollectionUpdateEventListener.class ); + + + private static EventType create(String name, Class listenerClass) { + return new EventType( 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 { @Override public Map run() { final Map typeByNameMap = new HashMap(); - 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 ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index 63e24f69ec..927740e8c2 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -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() { diff --git a/hibernate-core/src/test/java/org/hibernate/test/events/ClearEventListenerTest.java b/hibernate-core/src/test/java/org/hibernate/test/events/ClearEventListenerTest.java new file mode 100644 index 0000000000..a843d481b0 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/events/ClearEventListenerTest.java @@ -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) { + } + } + ); + } +}