diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/foreignkeys/Person.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/foreignkeys/Person.java index 516870d9e2..bf669603dd 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/foreignkeys/Person.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/foreignkeys/Person.java @@ -33,5 +33,5 @@ public class Person { joinColumns = @JoinColumn(name = "PERSON_ID", foreignKey = @ForeignKey(name = "PERSON_ID_FK")), inverseJoinColumns = @JoinColumn(name = "PHONE_ID", foreignKey = @ForeignKey(name = "PHONE_ID_FK")) ) - private List phones = new ArrayList<>(); + private List phones = new ArrayList(); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/foreignkeys/crossschema/SchemaTwoEntity.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/foreignkeys/crossschema/SchemaTwoEntity.java index 0cff64def0..45d64b1e1c 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/foreignkeys/crossschema/SchemaTwoEntity.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/foreignkeys/crossschema/SchemaTwoEntity.java @@ -26,5 +26,5 @@ public class SchemaTwoEntity { @OneToMany @JoinColumn - private Set schemaOneEntities = new HashSet<>(); + private Set schemaOneEntities = new HashSet(); } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaDeleteEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaDeleteEventListener.java index 5c730784ad..4e062abb89 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaDeleteEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaDeleteEventListener.java @@ -11,7 +11,7 @@ import java.io.Serializable; import org.hibernate.event.internal.DefaultDeleteEventListener; import org.hibernate.event.spi.DeleteEvent; import org.hibernate.event.spi.EventSource; -import org.hibernate.jpa.event.internal.jpa.CallbackRegistryConsumer; +import org.hibernate.jpa.event.spi.jpa.CallbackRegistryConsumer; import org.hibernate.jpa.event.spi.jpa.CallbackRegistry; import org.hibernate.persister.entity.EntityPersister; diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaFlushEntityEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaFlushEntityEventListener.java index 8240bf38ad..99ae17c4d1 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaFlushEntityEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaFlushEntityEventListener.java @@ -12,7 +12,7 @@ import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.Status; import org.hibernate.event.internal.DefaultFlushEntityEventListener; -import org.hibernate.jpa.event.internal.jpa.CallbackRegistryConsumer; +import org.hibernate.jpa.event.spi.jpa.CallbackRegistryConsumer; import org.hibernate.jpa.event.spi.jpa.CallbackRegistry; import org.hibernate.metadata.ClassMetadata; import org.hibernate.persister.entity.EntityPersister; diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaMergeEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaMergeEventListener.java index 5693280a92..7e0c4cfaa1 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaMergeEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaMergeEventListener.java @@ -10,7 +10,7 @@ import java.io.Serializable; import org.hibernate.event.internal.DefaultMergeEventListener; import org.hibernate.event.spi.EventSource; -import org.hibernate.jpa.event.internal.jpa.CallbackRegistryConsumer; +import org.hibernate.jpa.event.spi.jpa.CallbackRegistryConsumer; import org.hibernate.jpa.event.spi.jpa.CallbackRegistry; /** diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaPersistEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaPersistEventListener.java index 8d8bcfe7bc..db33d4763b 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaPersistEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaPersistEventListener.java @@ -15,7 +15,7 @@ import org.hibernate.engine.spi.CascadingAction; import org.hibernate.engine.spi.CascadingActions; import org.hibernate.event.internal.DefaultPersistEventListener; import org.hibernate.event.spi.EventSource; -import org.hibernate.jpa.event.internal.jpa.CallbackRegistryConsumer; +import org.hibernate.jpa.event.spi.jpa.CallbackRegistryConsumer; import org.hibernate.jpa.event.spi.jpa.CallbackRegistry; import org.hibernate.type.CollectionType; diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaPostDeleteEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaPostDeleteEventListener.java index 8ed010ab6b..f094af9eb0 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaPostDeleteEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaPostDeleteEventListener.java @@ -8,8 +8,9 @@ package org.hibernate.jpa.event.internal.core; import org.hibernate.event.spi.PostDeleteEvent; import org.hibernate.event.spi.PostDeleteEventListener; -import org.hibernate.jpa.event.internal.jpa.CallbackRegistryConsumer; +import org.hibernate.jpa.event.spi.jpa.CallbackRegistryConsumer; import org.hibernate.jpa.event.spi.jpa.CallbackRegistry; +import org.hibernate.jpa.event.spi.jpa.CallbackType; import org.hibernate.persister.entity.EntityPersister; /** @@ -37,6 +38,6 @@ public class JpaPostDeleteEventListener implements PostDeleteEventListener, Call @Override public boolean requiresPostCommitHanding(EntityPersister persister) { - return callbackRegistry.hasPostRemoveCallbacks( persister.getMappedClass() ); + return callbackRegistry.hasRegisteredCallbacks( persister.getMappedClass(), CallbackType.POST_REMOVE ); } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaPostInsertEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaPostInsertEventListener.java index 1eb1e6991b..720ebc13ff 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaPostInsertEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaPostInsertEventListener.java @@ -8,8 +8,9 @@ package org.hibernate.jpa.event.internal.core; import org.hibernate.event.spi.PostInsertEvent; import org.hibernate.event.spi.PostInsertEventListener; -import org.hibernate.jpa.event.internal.jpa.CallbackRegistryConsumer; +import org.hibernate.jpa.event.spi.jpa.CallbackRegistryConsumer; import org.hibernate.jpa.event.spi.jpa.CallbackRegistry; +import org.hibernate.jpa.event.spi.jpa.CallbackType; import org.hibernate.persister.entity.EntityPersister; /** @@ -40,6 +41,6 @@ public class JpaPostInsertEventListener implements PostInsertEventListener, Call @Override public boolean requiresPostCommitHanding(EntityPersister persister) { - return callbackRegistry.hasPostCreateCallbacks( persister.getMappedClass() ); + return callbackRegistry.hasRegisteredCallbacks( persister.getMappedClass(), CallbackType.POST_PERSIST ); } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaPostLoadEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaPostLoadEventListener.java index 334d9e50bd..9ab9e0e0cf 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaPostLoadEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaPostLoadEventListener.java @@ -8,7 +8,7 @@ package org.hibernate.jpa.event.internal.core; import org.hibernate.event.spi.PostLoadEvent; import org.hibernate.event.spi.PostLoadEventListener; -import org.hibernate.jpa.event.internal.jpa.CallbackRegistryConsumer; +import org.hibernate.jpa.event.spi.jpa.CallbackRegistryConsumer; import org.hibernate.jpa.event.spi.jpa.CallbackRegistry; /** diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaPostUpdateEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaPostUpdateEventListener.java index 65b8c69b13..2844ab7eec 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaPostUpdateEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaPostUpdateEventListener.java @@ -17,8 +17,9 @@ import org.hibernate.event.spi.PostCollectionUpdateEvent; import org.hibernate.event.spi.PostCollectionUpdateEventListener; import org.hibernate.event.spi.PostUpdateEvent; import org.hibernate.event.spi.PostUpdateEventListener; -import org.hibernate.jpa.event.internal.jpa.CallbackRegistryConsumer; +import org.hibernate.jpa.event.spi.jpa.CallbackRegistryConsumer; import org.hibernate.jpa.event.spi.jpa.CallbackRegistry; +import org.hibernate.jpa.event.spi.jpa.CallbackType; import org.hibernate.persister.entity.EntityPersister; /** @@ -62,7 +63,7 @@ public class JpaPostUpdateEventListener @Override public boolean requiresPostCommitHanding(EntityPersister persister) { - return callbackRegistry.hasPostUpdateCallbacks( persister.getMappedClass() ); + return callbackRegistry.hasRegisteredCallbacks( persister.getMappedClass(), CallbackType.POST_UPDATE ); } @Override diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaSaveEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaSaveEventListener.java index b7c8d19546..d72a7d9a2a 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaSaveEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaSaveEventListener.java @@ -10,7 +10,7 @@ import java.io.Serializable; import org.hibernate.event.internal.DefaultSaveEventListener; import org.hibernate.event.spi.EventSource; -import org.hibernate.jpa.event.internal.jpa.CallbackRegistryConsumer; +import org.hibernate.jpa.event.spi.jpa.CallbackRegistryConsumer; import org.hibernate.jpa.event.spi.jpa.CallbackRegistry; /** diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaSaveOrUpdateEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaSaveOrUpdateEventListener.java index 4d08b0acb6..73446a1805 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaSaveOrUpdateEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/core/JpaSaveOrUpdateEventListener.java @@ -10,7 +10,7 @@ import java.io.Serializable; import org.hibernate.event.internal.DefaultSaveOrUpdateEventListener; import org.hibernate.event.spi.EventSource; -import org.hibernate.jpa.event.internal.jpa.CallbackRegistryConsumer; +import org.hibernate.jpa.event.spi.jpa.CallbackRegistryConsumer; import org.hibernate.jpa.event.spi.jpa.CallbackRegistry; /** diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/AbstractCallback.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/AbstractCallback.java new file mode 100644 index 0000000000..cac0130a42 --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/AbstractCallback.java @@ -0,0 +1,31 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.jpa.event.internal.jpa; + +import org.hibernate.jpa.event.spi.jpa.Callback; +import org.hibernate.jpa.event.spi.jpa.CallbackType; + +/** + * @author Steve Ebersole + */ +public abstract class AbstractCallback implements Callback { + private final CallbackType callbackType; + + public AbstractCallback(CallbackType callbackType) { + this.callbackType = callbackType; + } + + @Override + public boolean isActive() { + return true; + } + + @Override + public CallbackType getCallbackType() { + return callbackType; + } +} diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/BeanManagerListenerFactory.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/BeanManagerListenerFactory.java deleted file mode 100644 index b046bde4f6..0000000000 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/BeanManagerListenerFactory.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.jpa.event.internal.jpa; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import javax.enterprise.context.spi.CreationalContext; -import javax.enterprise.inject.spi.AnnotatedType; -import javax.enterprise.inject.spi.BeanManager; -import javax.enterprise.inject.spi.InjectionTarget; - -import org.hibernate.jpa.event.spi.jpa.ListenerFactory; - -/** - * CID-based implementation of the ListenerFactory contract. Listener instances are kept in a map keyed by Class - * to achieve singleton-ness. - * - * @author Steve Ebersole - */ -public class BeanManagerListenerFactory implements ListenerFactory { - private final BeanManager beanManager; - private final Map listeners = new ConcurrentHashMap(); - - public static BeanManagerListenerFactory fromBeanManagerReference(Object beanManagerReference) { - return new BeanManagerListenerFactory( ( BeanManager ) beanManagerReference ); - } - - public BeanManagerListenerFactory(BeanManager beanManager) { - this.beanManager = beanManager; - } - - @Override - public T buildListener(Class listenerClass) { - BeanMetaData beanMetaData = listeners.get( listenerClass ); - if ( beanMetaData == null ) { - beanMetaData = new BeanMetaData( listenerClass ); - listeners.put( listenerClass, beanMetaData ); - } - return beanMetaData.instance; - } - - @Override - public void release() { - for ( BeanMetaData beanMetaData : listeners.values() ) { - beanMetaData.release(); - } - listeners.clear(); - } - - private class BeanMetaData { - private final InjectionTarget injectionTarget; - private final CreationalContext creationalContext; - private final T instance; - - private BeanMetaData(Class listenerClass) { - AnnotatedType annotatedType = beanManager.createAnnotatedType( listenerClass ); - this.injectionTarget = beanManager.createInjectionTarget( annotatedType ); - this.creationalContext = beanManager.createCreationalContext( null ); - - this.instance = injectionTarget.produce( creationalContext ); - injectionTarget.inject( this.instance, creationalContext ); - - injectionTarget.postConstruct( this.instance ); - } - - private void release() { - injectionTarget.preDestroy( instance ); - injectionTarget.dispose( instance ); - creationalContext.release(); - } - } -} diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/CallbackRegistryImpl.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/CallbackRegistryImpl.java index 94ba717696..35479cba3c 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/CallbackRegistryImpl.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/CallbackRegistryImpl.java @@ -8,16 +8,11 @@ package org.hibernate.jpa.event.internal.jpa; import java.util.HashMap; import javax.persistence.PersistenceException; -import javax.persistence.PostLoad; -import javax.persistence.PostPersist; -import javax.persistence.PostRemove; -import javax.persistence.PostUpdate; -import javax.persistence.PrePersist; -import javax.persistence.PreRemove; -import javax.persistence.PreUpdate; import org.hibernate.jpa.event.spi.jpa.Callback; import org.hibernate.jpa.event.spi.jpa.CallbackRegistry; +import org.hibernate.jpa.event.spi.jpa.CallbackType; +import org.hibernate.jpa.event.spi.jpa.EntityCallbackBuilder; /** * Keep track of all lifecycle callbacks and listeners for a given persistence unit @@ -26,7 +21,7 @@ import org.hibernate.jpa.event.spi.jpa.CallbackRegistry; * @author Steve Ebersole */ @SuppressWarnings({"unchecked", "serial"}) -public class CallbackRegistryImpl implements CallbackRegistry { +public class CallbackRegistryImpl implements CallbackRegistry, EntityCallbackBuilder.CallbackRegistrar { private HashMap preCreates = new HashMap(); private HashMap postCreates = new HashMap(); private HashMap preRemoves = new HashMap(); @@ -36,13 +31,27 @@ public class CallbackRegistryImpl implements CallbackRegistry { private HashMap postLoads = new HashMap(); @Override - public void preCreate(Object bean) { - callback( preCreates.get( bean.getClass() ), bean ); + public boolean hasRegisteredCallbacks(Class entityClass, CallbackType callbackType) { + final HashMap map = determineAppropriateCallbackMap( callbackType ); + return notEmpty( map.get( entityClass ) ); } @Override - public boolean hasPostCreateCallbacks(Class entityClass) { - return notEmpty( preCreates.get( entityClass ) ); + public void registerCallbacks(Class entityClass, Callback[] callbacks) { + if ( callbacks == null || callbacks.length == 0 ) { + return; + } + + final HashMap map = determineAppropriateCallbackMap( callbacks[0].getCallbackType() ); + if ( map.containsKey( entityClass ) ) { + throw new PersistenceException( "Error build callback listeners; entity [" + entityClass.getName() + " was already processed" ); + } + map.put( entityClass, callbacks ); + } + + @Override + public void preCreate(Object bean) { + callback( preCreates.get( bean.getClass() ), bean ); } private boolean notEmpty(Callback[] callbacks) { @@ -59,11 +68,6 @@ public class CallbackRegistryImpl implements CallbackRegistry { return callback( preUpdates.get( bean.getClass() ), bean ); } - @Override - public boolean hasPostUpdateCallbacks(Class entityClass) { - return notEmpty( postUpdates.get( entityClass ) ); - } - @Override public void postUpdate(Object bean) { callback( postUpdates.get( bean.getClass() ), bean ); @@ -74,11 +78,6 @@ public class CallbackRegistryImpl implements CallbackRegistry { callback( preRemoves.get( bean.getClass() ), bean ); } - @Override - public boolean hasPostRemoveCallbacks(Class entityClass) { - return notEmpty( postRemoves.get( entityClass ) ); - } - @Override public void postRemove(Object bean) { callback( postRemoves.get( bean.getClass() ), bean ); @@ -101,56 +100,36 @@ public class CallbackRegistryImpl implements CallbackRegistry { } } - @Override - public boolean hasRegisteredCallbacks(Class entityClass, Class annotationClass) { - final HashMap map = determineAppropriateCallbackMap( annotationClass ); - return map != null && map.containsKey( entityClass ); - } - - /** - * Great care should be taken calling this. Not a fan of it being public, but that is needed because of - * @param entityClass - * @param annotationClass - * @param callbacks - */ - public void addEntityCallbacks(Class entityClass, Class annotationClass, Callback[] callbacks) { - final HashMap map = determineAppropriateCallbackMap( annotationClass ); - if ( map.containsKey( entityClass ) ) { - throw new PersistenceException( "Error build callback listeners; entity [" + entityClass.getName() + " was already processed" ); - } - map.put( entityClass, callbacks ); - } - - private HashMap determineAppropriateCallbackMap(Class annotationClass) { - if ( PrePersist.class.equals( annotationClass ) ) { + private HashMap determineAppropriateCallbackMap(CallbackType callbackType) { + if ( callbackType == CallbackType.PRE_PERSIST ) { return preCreates; } - if ( PostPersist.class.equals( annotationClass ) ) { + if ( callbackType == CallbackType.POST_PERSIST ) { return postCreates; } - if ( PreRemove.class.equals( annotationClass ) ) { + if ( callbackType == CallbackType.PRE_REMOVE ) { return preRemoves; } - if ( PostRemove.class.equals( annotationClass ) ) { + if ( callbackType == CallbackType.POST_REMOVE ) { return postRemoves; } - if ( PreUpdate.class.equals( annotationClass ) ) { + if ( callbackType == CallbackType.PRE_UPDATE ) { return preUpdates; } - if ( PostUpdate.class.equals( annotationClass ) ) { + if ( callbackType == CallbackType.POST_UPDATE ) { return postUpdates; } - if ( PostLoad.class.equals( annotationClass ) ) { + if ( callbackType == CallbackType.POST_LOAD ) { return postLoads; } - throw new PersistenceException( "Unrecognized JPA callback annotation [" + annotationClass.getName() + "]" ); + throw new PersistenceException( "Unrecognized JPA callback type [" + callbackType + "]" ); } public void release() { @@ -165,4 +144,54 @@ public class CallbackRegistryImpl implements CallbackRegistry { postLoads.clear(); } + + + // deprecations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + @Override + public boolean hasPostCreateCallbacks(Class entityClass) { + return notEmpty( preCreates.get( entityClass ) ); + } + + @Override + public boolean hasPostUpdateCallbacks(Class entityClass) { + return notEmpty( postUpdates.get( entityClass ) ); + } + + @Override + public boolean hasPostRemoveCallbacks(Class entityClass) { + return notEmpty( postRemoves.get( entityClass ) ); + } + + @Override + public boolean hasRegisteredCallbacks(Class entityClass, Class annotationClass) { + final HashMap map = determineAppropriateCallbackMap( toCallbackType( annotationClass ) ); + return map != null && map.containsKey( entityClass ); + } + + private CallbackType toCallbackType(Class annotationClass) { + if ( annotationClass == CallbackType.POST_LOAD.getCallbackAnnotation() ) { + return CallbackType.POST_LOAD; + } + else if ( annotationClass == CallbackType.PRE_PERSIST.getCallbackAnnotation() ) { + return CallbackType.PRE_PERSIST; + } + else if ( annotationClass == CallbackType.POST_PERSIST.getCallbackAnnotation() ) { + return CallbackType.POST_PERSIST; + } + else if ( annotationClass == CallbackType.PRE_UPDATE.getCallbackAnnotation() ) { + return CallbackType.PRE_UPDATE; + } + else if ( annotationClass == CallbackType.POST_UPDATE.getCallbackAnnotation() ) { + return CallbackType.POST_UPDATE; + } + else if ( annotationClass == CallbackType.PRE_REMOVE.getCallbackAnnotation() ) { + return CallbackType.PRE_REMOVE; + } + else if ( annotationClass == CallbackType.POST_REMOVE.getCallbackAnnotation() ) { + return CallbackType.POST_REMOVE; + } + + throw new PersistenceException( "Unrecognized JPA callback annotation [" + annotationClass + "]" ); + } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/EntityCallback.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/EntityCallback.java index 56b389ab26..8e72c9543d 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/EntityCallback.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/EntityCallback.java @@ -10,6 +10,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.hibernate.jpa.event.spi.jpa.Callback; +import org.hibernate.jpa.event.spi.jpa.CallbackType; /** * Represents a JPA callback on the entity itself @@ -17,10 +18,11 @@ import org.hibernate.jpa.event.spi.jpa.Callback; * @author Kabir Khan * @author Steve Ebersole */ -public class EntityCallback implements Callback { - private Method callbackMethod; +public class EntityCallback extends AbstractCallback implements Callback { + private final Method callbackMethod; - public EntityCallback(Method callbackMethod) { + public EntityCallback(Method callbackMethod, CallbackType callbackType) { + super( callbackType ); this.callbackMethod = callbackMethod; } @@ -43,9 +45,4 @@ public class EntityCallback implements Callback { throw new RuntimeException( e ); } } - - @Override - public boolean isActive() { - return true; - } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/LegacyCallbackProcessor.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/EntityCallbackBuilderLegacyImpl.java similarity index 77% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/LegacyCallbackProcessor.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/EntityCallbackBuilderLegacyImpl.java index f7d0c9da72..f13bf170e9 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/LegacyCallbackProcessor.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/EntityCallbackBuilderLegacyImpl.java @@ -25,33 +25,36 @@ import org.hibernate.annotations.common.reflection.ReflectionManager; import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.annotations.common.reflection.XMethod; import org.hibernate.jpa.event.spi.jpa.Callback; +import org.hibernate.jpa.event.spi.jpa.CallbackType; +import org.hibernate.jpa.event.spi.jpa.EntityCallbackBuilder; import org.hibernate.jpa.event.spi.jpa.ListenerFactory; import org.jboss.logging.Logger; /** - * @author Kabir Khan + * EntityCallbackBuilder implementation using HCANN ReflectionManager. "legacy" in that + * we want to move to Jandex instead. + * * @author Steve Ebersole */ -public class LegacyCallbackProcessor implements CallbackProcessor { - private static final Logger log = Logger.getLogger( LegacyCallbackProcessor.class ); +public class EntityCallbackBuilderLegacyImpl implements EntityCallbackBuilder { + private static final Logger log = Logger.getLogger( EntityCallbackBuilderLegacyImpl.class ); private final ListenerFactory jpaListenerFactory; private final ReflectionManager reflectionManager; - public LegacyCallbackProcessor(ListenerFactory jpaListenerFactory, ReflectionManager reflectionManager) { + public EntityCallbackBuilderLegacyImpl(ListenerFactory jpaListenerFactory, ReflectionManager reflectionManager) { this.jpaListenerFactory = jpaListenerFactory; this.reflectionManager = reflectionManager; } @Override - public void processCallbacksForEntity(Object entityObject, CallbackRegistryImpl callbackRegistry) { - final String entityClassName = (String) entityObject; + public void buildCallbacksForEntity(String entityClassName, CallbackRegistrar callbackRegistrar) { try { final XClass entityXClass = reflectionManager.classForName( entityClassName ); final Class entityClass = reflectionManager.toClass( entityXClass ); - for ( Class annotationClass : CALLBACK_ANNOTATION_CLASSES ) { - if ( callbackRegistry.hasRegisteredCallbacks( entityClass, annotationClass ) ) { + for ( CallbackType callbackType : CallbackType.values() ) { + if ( callbackRegistrar.hasRegisteredCallbacks( entityClass, callbackType ) ) { // this most likely means we have a class mapped multiple times using the hbm.xml // "entity name" feature log.debugf( @@ -59,12 +62,12 @@ public class LegacyCallbackProcessor implements CallbackProcessor { "assuming this means the class was mapped twice " + "(using hbm.xml entity-name support) - skipping subsequent registrations", entityClassName, - annotationClass.getSimpleName() + callbackType.getCallbackAnnotation().getSimpleName() ); continue; } - final Callback[] callbacks = resolveCallbacks( entityXClass, annotationClass, reflectionManager ); - callbackRegistry.addEntityCallbacks( entityClass, annotationClass, callbacks ); + final Callback[] callbacks = resolveCallbacks( entityXClass, callbackType, reflectionManager ); + callbackRegistrar.registerCallbacks( entityClass, callbacks ); } } catch (ClassLoadingException e) { @@ -72,7 +75,12 @@ public class LegacyCallbackProcessor implements CallbackProcessor { } } - public Callback[] resolveCallbacks(XClass beanClass, Class annotation, ReflectionManager reflectionManager) { + @Override + public void release() { + // nothign to do + } + + public Callback[] resolveCallbacks(XClass beanClass, CallbackType callbackType, ReflectionManager reflectionManager) { List callbacks = new ArrayList(); List callbacksMethodNames = new ArrayList(); //used to track overridden methods List orderedListeners = new ArrayList(); @@ -83,26 +91,26 @@ public class LegacyCallbackProcessor implements CallbackProcessor { Callback callback = null; List methods = currentClazz.getDeclaredMethods(); for ( final XMethod xMethod : methods ) { - if ( xMethod.isAnnotationPresent( annotation ) ) { + if ( xMethod.isAnnotationPresent( callbackType.getCallbackAnnotation() ) ) { Method method = reflectionManager.toMethod( xMethod ); final String methodName = method.getName(); if ( !callbacksMethodNames.contains( methodName ) ) { //overridden method, remove the superclass overridden method if ( callback == null ) { - callback = new EntityCallback( method ); + callback = new EntityCallback( method, callbackType ); Class returnType = method.getReturnType(); Class[] args = method.getParameterTypes(); if ( returnType != Void.TYPE || args.length != 0 ) { throw new RuntimeException( - "Callback methods annotated on the bean class must return void and take no arguments: " + annotation - .getName() + " - " + xMethod + "Callback methods annotated on the bean class must return void and take no arguments: " + + callbackType.getCallbackAnnotation().getName() + " - " + xMethod ); } method.setAccessible( true ); log.debugf( "Adding %s as %s callback for entity %s", methodName, - annotation.getSimpleName(), + callbackType.getCallbackAnnotation().getSimpleName(), beanClass.getName() ); callbacks.add( 0, callback ); //superclass first @@ -111,7 +119,7 @@ public class LegacyCallbackProcessor implements CallbackProcessor { else { throw new PersistenceException( "You can only annotate one callback method with " - + annotation.getName() + " in bean class: " + beanClass.getName() + + callbackType.getCallbackAnnotation().getName() + " in bean class: " + beanClass.getName() ); } } @@ -152,20 +160,24 @@ public class LegacyCallbackProcessor implements CallbackProcessor { callbacksMethodNames = new ArrayList(); List methods = xListener.getDeclaredMethods(); for ( final XMethod xMethod : methods ) { - if ( xMethod.isAnnotationPresent( annotation ) ) { + if ( xMethod.isAnnotationPresent( callbackType.getCallbackAnnotation() ) ) { final Method method = reflectionManager.toMethod( xMethod ); final String methodName = method.getName(); if ( !callbacksMethodNames.contains( methodName ) ) { //overridden method, remove the superclass overridden method if ( callback == null ) { - callback = new ListenerCallback( jpaListenerFactory.buildListener( listener ), method ); + callback = new ListenerCallback( + jpaListenerFactory.buildListener( listener ), + method, + callbackType + ); Class returnType = method.getReturnType(); Class[] args = method.getParameterTypes(); if ( returnType != Void.TYPE || args.length != 1 ) { throw new PersistenceException( - "Callback methods annotated in a listener bean class must return void and take one argument: " + annotation - .getName() + " - " + method + "Callback methods annotated in a listener bean class must return void and take one argument: " + + callbackType.getCallbackAnnotation().getName() + " - " + method ); } if ( !method.isAccessible() ) { @@ -174,7 +186,7 @@ public class LegacyCallbackProcessor implements CallbackProcessor { log.debugf( "Adding %s as %s callback for entity %s", methodName, - annotation.getSimpleName(), + callbackType.getCallbackAnnotation().getSimpleName(), beanClass.getName() ); callbacks.add( 0, callback ); // listeners first @@ -182,8 +194,9 @@ public class LegacyCallbackProcessor implements CallbackProcessor { else { throw new PersistenceException( "You can only annotate one callback method with " - + annotation.getName() + " in bean class: " + beanClass.getName() + " and callback listener: " - + listener.getName() + + callbackType.getCallbackAnnotation().getName() + + " in bean class: " + beanClass.getName() + + " and callback listener: " + listener.getName() ); } } @@ -232,9 +245,4 @@ public class LegacyCallbackProcessor implements CallbackProcessor { } } } - - @Override - public void release() { - // nothing to do here - } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/ListenerCallback.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/ListenerCallback.java index 7abcaf5b7b..946eda3efa 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/ListenerCallback.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/ListenerCallback.java @@ -10,6 +10,8 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.hibernate.jpa.event.spi.jpa.Callback; +import org.hibernate.jpa.event.spi.jpa.CallbackType; +import org.hibernate.jpa.event.spi.jpa.Listener; /** * Represents a JPA callback using a dedicated listener @@ -17,11 +19,12 @@ import org.hibernate.jpa.event.spi.jpa.Callback; * @author Kabir Khan * @author Steve Ebersole */ -public class ListenerCallback implements Callback { +public class ListenerCallback extends AbstractCallback implements Callback { private final Method callbackMethod; - private final Object listenerInstance; + private final Listener listenerInstance; - public ListenerCallback(Object listenerInstance, Method callbackMethod) { + public ListenerCallback(Listener listenerInstance, Method callbackMethod, CallbackType callbackType) { + super( callbackType ); this.listenerInstance = listenerInstance; this.callbackMethod = callbackMethod; } @@ -29,7 +32,7 @@ public class ListenerCallback implements Callback { @Override public boolean performCallback(Object entity) { try { - callbackMethod.invoke( listenerInstance, entity ); + callbackMethod.invoke( listenerInstance.getListener(), entity ); return true; } catch (InvocationTargetException e) { @@ -45,9 +48,4 @@ public class ListenerCallback implements Callback { throw new RuntimeException( e ); } } - - @Override - public boolean isActive() { - return true; - } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/ListenerFactoryBeanManagerImpl.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/ListenerFactoryBeanManagerImpl.java new file mode 100644 index 0000000000..bb996a4e60 --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/ListenerFactoryBeanManagerImpl.java @@ -0,0 +1,161 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.jpa.event.internal.jpa; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.inject.spi.AnnotatedType; +import javax.enterprise.inject.spi.BeanManager; +import javax.enterprise.inject.spi.InjectionTarget; + +import org.hibernate.HibernateException; +import org.hibernate.jpa.event.spi.jpa.ExtendedBeanManager; +import org.hibernate.jpa.event.spi.jpa.Listener; +import org.hibernate.jpa.event.spi.jpa.ListenerFactory; + +/** + * CDI-based implementation of the ListenerFactory contract. Listener instances are + * kept in a map keyed by Class to ensure single-instance-ness. + * + * @author Steve Ebersole + */ +public class ListenerFactoryBeanManagerImpl implements ListenerFactory, ExtendedBeanManager.LifecycleListener { + private final BeanManager beanManager; + private final boolean extendedBm; + + private final Map listenerMap = new ConcurrentHashMap(); + + public static ListenerFactoryBeanManagerImpl fromBeanManagerReference(Object reference) { + return new ListenerFactoryBeanManagerImpl( (BeanManager) reference ); + } + + public ListenerFactoryBeanManagerImpl(BeanManager beanManager) { + this.beanManager = beanManager; + if ( beanManager instanceof ExtendedBeanManager ) { + ( (ExtendedBeanManager) beanManager ).registerLifecycleListener( this ); + extendedBm = true; + } + else { + extendedBm = false; + } + } + + @Override + @SuppressWarnings("unchecked") + public Listener buildListener(Class listenerClass) { + ListenerImplementor listenerImpl = listenerMap.get( listenerClass ); + if ( listenerImpl == null ) { + listenerImpl = makeListener( listenerClass ); + listenerMap.put( listenerClass, listenerImpl ); + } + return (Listener) listenerImpl; + } + + private ListenerImplementor makeListener(Class listenerClass) { + if ( extendedBm ) { + return new ListenerExtendedImpl( listenerClass ); + } + else { + return new ListenerBasicImpl( listenerClass ); + } + } + + @Override + public void release() { + for ( ListenerImplementor listenerImpl : listenerMap.values() ) { + listenerImpl.release(); + } + listenerMap.clear(); + } + + @Override + public void beanManagerInitialized() { + for ( ListenerImplementor listenerImpl : listenerMap.values() ) { + // if the entries are not ListenerExtendedImpl instances we have serious issues... + ( (ListenerExtendedImpl) listenerImpl ).initialize(); + } + } + + private interface ListenerImplementor extends Listener { + void release(); + } + + private class ListenerBasicImpl implements ListenerImplementor { + private final InjectionTarget injectionTarget; + private final CreationalContext creationalContext; + private final T listenerInstance; + + private ListenerBasicImpl(Class listenerClass) { + AnnotatedType annotatedType = beanManager.createAnnotatedType( listenerClass ); + this.injectionTarget = beanManager.createInjectionTarget( annotatedType ); + this.creationalContext = beanManager.createCreationalContext( null ); + + this.listenerInstance = injectionTarget.produce( creationalContext ); + injectionTarget.inject( this.listenerInstance, creationalContext ); + + injectionTarget.postConstruct( this.listenerInstance ); + } + + @Override + public T getListener() { + return listenerInstance; + } + + public void release() { + injectionTarget.preDestroy( listenerInstance ); + injectionTarget.dispose( listenerInstance ); + creationalContext.release(); + } + } + + private class ListenerExtendedImpl implements ListenerImplementor { + private final Class listenerClass; + + private boolean initialized = false; + + private InjectionTarget injectionTarget; + private CreationalContext creationalContext; + private T listenerInstance; + + private ListenerExtendedImpl(Class listenerClass) { + this.listenerClass = listenerClass; + } + + public void initialize() { + AnnotatedType annotatedType = beanManager.createAnnotatedType( listenerClass ); + this.injectionTarget = beanManager.createInjectionTarget( annotatedType ); + this.creationalContext = beanManager.createCreationalContext( null ); + + this.listenerInstance = injectionTarget.produce( creationalContext ); + injectionTarget.inject( this.listenerInstance, creationalContext ); + + injectionTarget.postConstruct( this.listenerInstance ); + + this.initialized = true; + } + + @Override + public T getListener() { + if ( !initialized ) { + throw new HibernateException( "CDI not initialized as expected" ); + } + return listenerInstance; + } + + public void release() { + if ( !initialized ) { + // log + return; + } + + injectionTarget.preDestroy( listenerInstance ); + injectionTarget.dispose( listenerInstance ); + creationalContext.release(); + } + } +} diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/StandardListenerFactory.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/ListenerFactoryStandardImpl.java similarity index 51% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/StandardListenerFactory.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/ListenerFactoryStandardImpl.java index 85a2cd1839..a4ca4ea8ed 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/StandardListenerFactory.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/ListenerFactoryStandardImpl.java @@ -9,6 +9,7 @@ package org.hibernate.jpa.event.internal.jpa; import java.util.concurrent.ConcurrentHashMap; import javax.persistence.PersistenceException; +import org.hibernate.jpa.event.spi.jpa.Listener; import org.hibernate.jpa.event.spi.jpa.ListenerFactory; /** @@ -17,17 +18,18 @@ import org.hibernate.jpa.event.spi.jpa.ListenerFactory; * * @author Steve Ebersole */ -public class StandardListenerFactory implements ListenerFactory { +public class ListenerFactoryStandardImpl implements ListenerFactory { - private final ConcurrentHashMap listenerInstances = new ConcurrentHashMap(); + private final ConcurrentHashMap listenerInstances = new ConcurrentHashMap(); @Override @SuppressWarnings("unchecked") - public T buildListener(Class listenerClass) { - Object listenerInstance = listenerInstances.get( listenerClass ); - if ( listenerInstance == null ) { + public Listener buildListener(Class listenerClass) { + Listener listenerImpl = listenerInstances.get( listenerClass ); + if ( listenerImpl == null ) { try { - listenerInstance = listenerClass.newInstance(); + T listenerInstance = listenerClass.newInstance(); + listenerImpl = new ListenerImpl( listenerInstance ); } catch (Exception e) { throw new PersistenceException( @@ -35,16 +37,32 @@ public class StandardListenerFactory implements ListenerFactory { e ); } - Object existing = listenerInstances.putIfAbsent( listenerClass, listenerInstance ); + Listener existing = listenerInstances.putIfAbsent( + listenerClass, + listenerImpl + ); if ( existing != null ) { - listenerInstance = existing; + listenerImpl = existing; } } - return (T) listenerInstance; + return (Listener) listenerImpl; } @Override public void release() { listenerInstances.clear(); } + + private static class ListenerImpl implements Listener { + private final T listenerInstance; + + public ListenerImpl(T listenerInstance) { + this.listenerInstance = listenerInstance; + } + + @Override + public T getListener() { + return listenerInstance; + } + } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/JpaIntegrator.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/JpaIntegrator.java index 49a766b168..d2c5d545c3 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/JpaIntegrator.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/JpaIntegrator.java @@ -40,11 +40,11 @@ import org.hibernate.jpa.event.internal.core.JpaPostLoadEventListener; import org.hibernate.jpa.event.internal.core.JpaPostUpdateEventListener; import org.hibernate.jpa.event.internal.core.JpaSaveEventListener; import org.hibernate.jpa.event.internal.core.JpaSaveOrUpdateEventListener; -import org.hibernate.jpa.event.internal.jpa.CallbackProcessor; -import org.hibernate.jpa.event.internal.jpa.CallbackRegistryConsumer; +import org.hibernate.jpa.event.internal.jpa.EntityCallbackBuilderLegacyImpl; +import org.hibernate.jpa.event.spi.jpa.CallbackRegistryConsumer; import org.hibernate.jpa.event.internal.jpa.CallbackRegistryImpl; -import org.hibernate.jpa.event.internal.jpa.LegacyCallbackProcessor; -import org.hibernate.jpa.event.internal.jpa.StandardListenerFactory; +import org.hibernate.jpa.event.internal.jpa.ListenerFactoryStandardImpl; +import org.hibernate.jpa.event.spi.jpa.EntityCallbackBuilder; import org.hibernate.jpa.event.spi.jpa.ListenerFactory; import org.hibernate.mapping.PersistentClass; import org.hibernate.service.spi.ServiceRegistryImplementor; @@ -57,7 +57,7 @@ import org.hibernate.service.spi.SessionFactoryServiceRegistry; */ public class JpaIntegrator implements Integrator { private ListenerFactory jpaListenerFactory; - private CallbackProcessor callbackProcessor; + private EntityCallbackBuilder entityCallbackBuilder; private CallbackRegistryImpl callbackRegistry; private static final DuplicationStrategy JPA_DUPLICATION_STRATEGY = new JPADuplicationStrategy(); @@ -128,16 +128,16 @@ public class JpaIntegrator implements Integrator { this.callbackRegistry = new CallbackRegistryImpl(); final Object beanManagerRef = sessionFactory.getSessionFactoryOptions().getBeanManagerReference(); this.jpaListenerFactory = beanManagerRef == null - ? new StandardListenerFactory() + ? new ListenerFactoryStandardImpl() : buildBeanManagerListenerFactory( beanManagerRef ); - this.callbackProcessor = new LegacyCallbackProcessor( jpaListenerFactory, reflectionManager ); + this.entityCallbackBuilder = new EntityCallbackBuilderLegacyImpl( jpaListenerFactory, reflectionManager ); for ( PersistentClass persistentClass : metadata.getEntityBindings() ) { if ( persistentClass.getClassName() == null ) { // we can have non java class persisted by hibernate continue; } - callbackProcessor.processCallbacksForEntity( persistentClass.getClassName(), callbackRegistry ); + entityCallbackBuilder.buildCallbacksForEntity( persistentClass.getClassName(), callbackRegistry ); } for ( EventType eventType : EventType.values() ) { @@ -150,7 +150,7 @@ public class JpaIntegrator implements Integrator { } } - private static final String CDI_LISTENER_FACTORY_CLASS = "org.hibernate.jpa.event.internal.jpa.BeanManagerListenerFactory"; + private static final String CDI_LISTENER_FACTORY_CLASS = "org.hibernate.jpa.event.internal.jpa.ListenerFactoryBeanManagerImpl"; private ListenerFactory buildBeanManagerListenerFactory(Object beanManagerRef) { try { @@ -191,8 +191,8 @@ public class JpaIntegrator implements Integrator { if ( callbackRegistry != null ) { callbackRegistry.release(); } - if ( callbackProcessor != null ) { - callbackProcessor.release(); + if ( entityCallbackBuilder != null ) { + entityCallbackBuilder.release(); } if ( jpaListenerFactory != null ) { jpaListenerFactory.release(); diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/Callback.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/Callback.java index ea30797c94..98b9ded213 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/Callback.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/Callback.java @@ -9,12 +9,29 @@ package org.hibernate.jpa.event.spi.jpa; import java.io.Serializable; /** - * Represents a JPA event callback. + * Represents a JPA event callback (the method). + *

+ * Generally there are 2 flavors of this; either an annotated method on the entity itself + * or an annotated method on a separate "listener" class. This contract unifies both of + * these cases. * * @author Kabir Khan * @author Steve Ebersole */ public interface Callback extends Serializable { + /** + * Is this callback active (will it do anything)? + * + * @return {@code true} if the callback is active, {@code false} otherwise. + * + * @deprecated I can actually find no usages of this method and have no idea + * why it is here :) + */ + @Deprecated + boolean isActive(); + + CallbackType getCallbackType(); + /** * Contract for performing the callback * @@ -22,12 +39,5 @@ public interface Callback extends Serializable { * * @return Did a callback actually happen? */ - public boolean performCallback(Object entity); - - /** - * Is this callback active (will it do anything)? - * - * @return - */ - public boolean isActive(); + boolean performCallback(Object entity); } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/CallbackRegistry.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/CallbackRegistry.java index 6a8f8d3f0c..7beb223651 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/CallbackRegistry.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/CallbackRegistry.java @@ -9,22 +9,57 @@ package org.hibernate.jpa.event.spi.jpa; import java.io.Serializable; /** + * Registry of Callbacks by entity and type + * * @author Steve Ebersole */ public interface CallbackRegistry extends Serializable { + /** + * Do we have any registered callbacks of the given type for the given entity? + * + * @param entityClass The entity Class to check against + * @param callbackType The type of callback to look for + * + * @return {@code true} indicates there are already registered callbacks of + * that type for that class; {@code false} indicates there are not. + */ + boolean hasRegisteredCallbacks(Class entityClass, CallbackType callbackType); + void preCreate(Object entity); - boolean hasPostCreateCallbacks(Class entityClass); void postCreate(Object entity); boolean preUpdate(Object entity); - boolean hasPostUpdateCallbacks(Class entityClass); void postUpdate(Object entity); void preRemove(Object entity); - boolean hasPostRemoveCallbacks(Class entityClass); void postRemove(Object entity); boolean postLoad(Object entity); + /** + * @deprecated Use {@link #hasRegisteredCallbacks(Class, CallbackType)} instead passing + * {@link CallbackType#POST_PERSIST} + */ + @Deprecated + boolean hasPostCreateCallbacks(Class entityClass); + + /** + * @deprecated Use {@link #hasRegisteredCallbacks(Class, CallbackType)} instead passing + * {@link CallbackType#POST_UPDATE} + */ + @Deprecated + boolean hasPostUpdateCallbacks(Class entityClass); + + /** + * @deprecated Use {@link #hasRegisteredCallbacks(Class, CallbackType)} instead passing + * {@link CallbackType#POST_REMOVE} + */ + @Deprecated + boolean hasPostRemoveCallbacks(Class entityClass); + + /** + * @deprecated Use {@link #hasRegisteredCallbacks(Class, CallbackType)} instead. + */ + @Deprecated boolean hasRegisteredCallbacks(Class entityClass, Class annotationClass); } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/CallbackRegistryConsumer.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/CallbackRegistryConsumer.java similarity index 78% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/CallbackRegistryConsumer.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/CallbackRegistryConsumer.java index d50ace66dc..4a56666024 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/internal/jpa/CallbackRegistryConsumer.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/CallbackRegistryConsumer.java @@ -4,10 +4,9 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.event.internal.jpa; +package org.hibernate.jpa.event.spi.jpa; import org.hibernate.jpa.event.internal.core.HibernateEntityManagerEventListener; -import org.hibernate.jpa.event.spi.jpa.CallbackRegistry; /** * Contract for injecting the registry of Callbacks into event listeners. @@ -21,5 +20,5 @@ public interface CallbackRegistryConsumer extends HibernateEntityManagerEventLis * * @param callbackRegistry The CallbackRegistry */ - public void injectCallbackRegistry(CallbackRegistry callbackRegistry); + void injectCallbackRegistry(CallbackRegistry callbackRegistry); } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/CallbackType.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/CallbackType.java new file mode 100644 index 0000000000..34ec1a1f70 --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/CallbackType.java @@ -0,0 +1,40 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.jpa.event.spi.jpa; + +import java.lang.annotation.Annotation; +import javax.persistence.PostLoad; +import javax.persistence.PostPersist; +import javax.persistence.PostRemove; +import javax.persistence.PostUpdate; +import javax.persistence.PrePersist; +import javax.persistence.PreRemove; +import javax.persistence.PreUpdate; + +/** + * @author Steve Ebersole + */ +public enum CallbackType { + PRE_UPDATE( PreUpdate.class ), + POST_UPDATE( PostUpdate.class ), + PRE_PERSIST( PrePersist.class ), + POST_PERSIST( PostPersist.class ), + PRE_REMOVE( PreRemove.class ), + POST_REMOVE( PostRemove.class ), + POST_LOAD( PostLoad.class ) + ; + + private Class callbackAnnotation; + + CallbackType(Class callbackAnnotation) { + this.callbackAnnotation = callbackAnnotation; + } + + public Class getCallbackAnnotation() { + return callbackAnnotation; + } +} diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/EntityCallbackBuilder.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/EntityCallbackBuilder.java new file mode 100644 index 0000000000..a0bcf7f30e --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/EntityCallbackBuilder.java @@ -0,0 +1,32 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.jpa.event.spi.jpa; + +/** + * Contract for walking an entity hierarchy and building a list of JPA callbacks + * + * @author Steve Ebersole + */ +public interface EntityCallbackBuilder { + /** + * Represents the target of JPA callback registrations as part the EntityCallbackBuilder + */ + interface CallbackRegistrar extends CallbackRegistry { + + /** + * Register the callback against the given entity. + * + * @param entityClass The entity Class to register the Callbacks against + * @param callbacks The Callbacks to register against the given entity Class + */ + void registerCallbacks(Class entityClass, Callback[] callbacks); + } + + void buildCallbacksForEntity(String entityName, CallbackRegistrar callbackRegistrar); + + void release(); +} diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/ExtendedBeanManager.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/ExtendedBeanManager.java new file mode 100644 index 0000000000..4e598654f6 --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/ExtendedBeanManager.java @@ -0,0 +1,20 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.jpa.event.spi.jpa; + +/** + * @author Steve Ebersole + */ +public interface ExtendedBeanManager { + void registerLifecycleListener(LifecycleListener lifecycleListener); + + /** + */ + interface LifecycleListener { + void beanManagerInitialized(); + } +} diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/Listener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/Listener.java new file mode 100644 index 0000000000..29ba58b01e --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/Listener.java @@ -0,0 +1,17 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.jpa.event.spi.jpa; + +/** + * Encapsulates access to the listener instance for listener callbacks + * ({@link javax.persistence.EntityListeners}). + * + * @author Steve Ebersole + */ +public interface Listener { + T getListener(); +} diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/ListenerFactory.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/ListenerFactory.java index e27c536ef4..47c451ffd3 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/ListenerFactory.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/event/spi/jpa/ListenerFactory.java @@ -7,12 +7,11 @@ package org.hibernate.jpa.event.spi.jpa; /** - * Factory for building instances user-specified event listeners. + * Factory for building instances of callback listener classes. * * @author Steve Ebersole */ public interface ListenerFactory { - public T buildListener(Class listenerClass); - - public void release(); + Listener buildListener(Class listenerClass); + void release(); }