diff --git a/hibernate-entitymanager/hibernate-entitymanager.gradle b/hibernate-entitymanager/hibernate-entitymanager.gradle index c90834f6fc..fb219fe5a3 100644 --- a/hibernate-entitymanager/hibernate-entitymanager.gradle +++ b/hibernate-entitymanager/hibernate-entitymanager.gradle @@ -9,11 +9,16 @@ dependencies { compile( libraries.jpa ) compile( libraries.jta ) compile( libraries.javassist ) + provided( "javax.enterprise:cdi-api:1.0-SP4" ) testCompile( project(':hibernate-testing') ) testCompile( libraries.shrinkwrap_api ) testCompile( libraries.shrinkwrap ) testCompile( libraries.validation ) testRuntime( libraries.validator ) + testCompile( "org.jboss.weld.arquillian.container:arquillian-weld-ee-embedded-1.1:1.1.2.Final" ) + testCompile( "org.jboss.weld:weld-core:1.1.9.Final" ) + testRuntime( "org.glassfish.web:el-impl:2.1.2-b04" ) + testRuntime( "org.jboss.ejb3:jboss-ejb3-api:3.1.0" ) } //////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/AvailableSettings.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/AvailableSettings.java index b75fa98d85..35ea9ba54f 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/AvailableSettings.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/AvailableSettings.java @@ -187,6 +187,11 @@ public interface AvailableSettings { */ public static final String REMOVE_VALIDATION_GROUP = "javax.persistence.validation.group.pre-remove"; + /** + * Used to pass along the CDI BeanManager, if any, to be used. + */ + public static final String CDI_BEAN_MANAGER = "javax.persistence.bean.manager"; + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Hibernate specific settings diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/Callback.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/Callback.java deleted file mode 100644 index 6c6a697968..0000000000 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/Callback.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * Copyright (c) 2009-2011, 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.jpa.internal.event; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; -import java.util.StringTokenizer; - -import org.hibernate.internal.util.ReflectHelper; - -/** - * @author Kabir Khan - */ -public abstract class Callback implements Serializable { - transient protected Method callbackMethod; - - public Callback(Method callbackMethod) { - this.callbackMethod = callbackMethod; - } - - public Method getCallbackMethod() { - return callbackMethod; - } - - public abstract void invoke(Object bean); - - private void writeObject(ObjectOutputStream oos) throws IOException { - oos.defaultWriteObject(); - oos.writeObject( callbackMethod.toGenericString() ); - } - - private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { - ois.defaultReadObject(); - String signature = (String) ois.readObject(); - StringTokenizer st = new StringTokenizer( signature, " ", false ); - String usefulSignature = null; - while ( st.hasMoreElements() ) usefulSignature = (String) st.nextElement(); - int parenthesis = usefulSignature.indexOf( "(" ); - String methodAndClass = usefulSignature.substring( 0, parenthesis ); - int lastDot = methodAndClass.lastIndexOf( "." ); - String clazzName = methodAndClass.substring( 0, lastDot ); - Class callbackClass = ReflectHelper.classForName( clazzName, this.getClass() ); - String parametersString = usefulSignature.substring( parenthesis + 1, usefulSignature.length() - 1 ); - st = new StringTokenizer( parametersString, ", ", false ); - List parameters = new ArrayList(); - while ( st.hasMoreElements() ) { - String parameter = (String) st.nextElement(); - parameters.add( ReflectHelper.classForName( parameter, this.getClass() ) ); - } - String methodName = methodAndClass.substring( lastDot + 1, methodAndClass.length() ); - try { - callbackMethod = callbackClass.getDeclaredMethod( - methodName, - parameters.toArray( new Class[ parameters.size() ] ) - ); - if ( ! callbackMethod.isAccessible() ) { - callbackMethod.setAccessible( true ); - } - } - catch (NoSuchMethodException e) { - throw new IOException( "Unable to get EJB3 callback method: " + signature + ", cause: " + e ); - } - } -} diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaIntegrator.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaIntegrator.java index 5bc9ac4e6e..f4c17067f3 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaIntegrator.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaIntegrator.java @@ -23,12 +23,11 @@ */ package org.hibernate.jpa.internal.event; +import javax.enterprise.inject.spi.BeanManager; import java.util.Iterator; import java.util.Map; import org.hibernate.HibernateException; -import org.hibernate.MappingException; -import org.hibernate.annotations.common.reflection.ReflectionManager; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; import org.hibernate.engine.spi.CascadeStyles; @@ -41,6 +40,28 @@ import org.hibernate.event.service.spi.EventListenerRegistry; import org.hibernate.event.spi.EventType; import org.hibernate.integrator.spi.Integrator; import org.hibernate.jpa.AvailableSettings; +import org.hibernate.jpa.internal.event.core.HibernateEntityManagerEventListener; +import org.hibernate.jpa.internal.event.core.JpaAutoFlushEventListener; +import org.hibernate.jpa.internal.event.core.JpaDeleteEventListener; +import org.hibernate.jpa.internal.event.core.JpaFlushEntityEventListener; +import org.hibernate.jpa.internal.event.core.JpaFlushEventListener; +import org.hibernate.jpa.internal.event.core.JpaMergeEventListener; +import org.hibernate.jpa.internal.event.core.JpaPersistEventListener; +import org.hibernate.jpa.internal.event.core.JpaPersistOnFlushEventListener; +import org.hibernate.jpa.internal.event.core.JpaPostDeleteEventListener; +import org.hibernate.jpa.internal.event.core.JpaPostInsertEventListener; +import org.hibernate.jpa.internal.event.core.JpaPostLoadEventListener; +import org.hibernate.jpa.internal.event.core.JpaPostUpdateEventListener; +import org.hibernate.jpa.internal.event.core.JpaSaveEventListener; +import org.hibernate.jpa.internal.event.core.JpaSaveOrUpdateEventListener; +import org.hibernate.jpa.internal.event.jpa.BeanManagerListenerFactory; +import org.hibernate.jpa.internal.event.jpa.CallbackProcessor; +import org.hibernate.jpa.internal.event.jpa.CallbackProcessorImpl; +import org.hibernate.jpa.internal.event.jpa.CallbackRegistryConsumer; +import org.hibernate.jpa.internal.event.jpa.CallbackRegistry; +import org.hibernate.jpa.internal.event.jpa.LegacyCallbackProcessor; +import org.hibernate.jpa.internal.event.jpa.ListenerFactory; +import org.hibernate.jpa.internal.event.jpa.StandardListenerFactory; import org.hibernate.mapping.PersistentClass; import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.metamodel.source.MetadataImplementor; @@ -50,16 +71,19 @@ import org.hibernate.secure.internal.JACCPreLoadEventListener; import org.hibernate.secure.internal.JACCPreUpdateEventListener; import org.hibernate.secure.internal.JACCSecurityListener; import org.hibernate.service.classloading.spi.ClassLoaderService; -import org.hibernate.service.classloading.spi.ClassLoadingException; import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.service.spi.SessionFactoryServiceRegistry; /** - * Prepare the HEM-specific event listeners. + * Hibernate EntityManager specific Integrator, performing JPA setup. * * @author Steve Ebersole */ public class JpaIntegrator implements Integrator { + private ListenerFactory jpaListenerFactory; + private CallbackProcessor callbackProcessor; + private CallbackRegistry callbackRegistry; + private static final DuplicationStrategy JPA_DUPLICATION_STRATEGY = new DuplicationStrategy() { @Override public boolean areMatch(Object listener, Object original) { @@ -109,6 +133,7 @@ public class JpaIntegrator implements Integrator { } ); + // then prepare listeners final EventListenerRegistry eventListenerRegistry = serviceRegistry.getService( EventListenerRegistry.class ); @@ -159,28 +184,30 @@ public class JpaIntegrator implements Integrator { } } - final EntityCallbackHandler callbackHandler = new EntityCallbackHandler(); + // handle JPA "entity listener classes"... + + this.callbackRegistry = new CallbackRegistry(); + final BeanManager beanManager = (BeanManager) configuration.getProperties().get( AvailableSettings.CDI_BEAN_MANAGER ); + this.jpaListenerFactory = beanManager == null + ? new StandardListenerFactory() + : new BeanManagerListenerFactory( beanManager ); + this.callbackProcessor = new LegacyCallbackProcessor( jpaListenerFactory, configuration.getReflectionManager() ); + Iterator classes = configuration.getClassMappings(); - ReflectionManager reflectionManager = configuration.getReflectionManager(); while ( classes.hasNext() ) { - PersistentClass clazz = (PersistentClass) classes.next(); + final PersistentClass clazz = (PersistentClass) classes.next(); if ( clazz.getClassName() == null ) { - //we can have non java class persisted by hibernate + // we can have non java class persisted by hibernate continue; } - try { - callbackHandler.add( reflectionManager.classForName( clazz.getClassName(), this.getClass() ), reflectionManager ); - } - catch (ClassNotFoundException e) { - throw new MappingException( "entity class not found: " + clazz.getNodeName(), e ); - } + callbackProcessor.processCallbacksForEntity( clazz.getClassName(), callbackRegistry ); } for ( EventType eventType : EventType.values() ) { final EventListenerGroup eventListenerGroup = eventListenerRegistry.getEventListenerGroup( eventType ); for ( Object listener : eventListenerGroup.listeners() ) { - if ( CallbackHandlerConsumer.class.isInstance( listener ) ) { - ( (CallbackHandlerConsumer) listener ).setCallbackHandler( callbackHandler ); + if ( CallbackRegistryConsumer.class.isInstance( listener ) ) { + ( (CallbackRegistryConsumer) listener ).injectCallbackRegistry( callbackRegistry ); } } } @@ -258,34 +285,40 @@ public class JpaIntegrator implements Integrator { } } - final EntityCallbackHandler callbackHandler = new EntityCallbackHandler(); - ClassLoaderService classLoaderSvc = serviceRegistry.getService(ClassLoaderService.class); - for (EntityBinding binding : metadata.getEntityBindings()) { - String name = binding.getEntity().getName(); // Should this be getClassName()? - if (name == null) { - //we can have non java class persisted by hibernate - continue; - } - try { - callbackHandler.add(classLoaderSvc.classForName(name), classLoaderSvc, binding); - } - catch (ClassLoadingException error) { - throw new MappingException( "entity class not found: " + name, error ); + // handle JPA "entity listener classes"... + + this.callbackRegistry = new CallbackRegistry(); + final BeanManager beanManager = (BeanManager) sessionFactory.getProperties().get( AvailableSettings.CDI_BEAN_MANAGER ); + this.jpaListenerFactory = beanManager == null + ? new StandardListenerFactory() + : new BeanManagerListenerFactory( beanManager ); + this.callbackProcessor = new CallbackProcessorImpl( jpaListenerFactory, metadata, serviceRegistry ); + + for ( EntityBinding binding : metadata.getEntityBindings() ) { + callbackProcessor.processCallbacksForEntity( binding, callbackRegistry ); + } + + for ( EventType eventType : EventType.values() ) { + final EventListenerGroup eventListenerGroup = eventListenerRegistry.getEventListenerGroup( eventType ); + for ( Object listener : eventListenerGroup.listeners() ) { + if ( CallbackRegistryConsumer.class.isInstance( listener ) ) { + ( (CallbackRegistryConsumer) listener ).injectCallbackRegistry( callbackRegistry ); + } } } -// -// for ( EventType eventType : EventType.values() ) { -// final EventListenerGroup eventListenerGroup = eventListenerRegistry.getEventListenerGroup( eventType ); -// for ( Object listener : eventListenerGroup.listeners() ) { -// if ( CallbackHandlerConsumer.class.isInstance( listener ) ) { -// ( (CallbackHandlerConsumer) listener ).setCallbackHandler( callbackHandler ); -// } -// } -// } } @Override public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) { + if ( callbackRegistry != null ) { + callbackRegistry.release(); + } + if ( callbackProcessor != null ) { + callbackProcessor.release(); + } + if ( jpaListenerFactory != null ) { + jpaListenerFactory.release(); + } } private Object instantiate(String listenerImpl, ServiceRegistryImplementor serviceRegistry) { diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/HibernateEntityManagerEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/HibernateEntityManagerEventListener.java similarity index 96% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/HibernateEntityManagerEventListener.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/HibernateEntityManagerEventListener.java index eb42886b10..4ddf11a78a 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/HibernateEntityManagerEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/HibernateEntityManagerEventListener.java @@ -21,7 +21,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.internal.event; +package org.hibernate.jpa.internal.event.core; /** * Marker interface for handling listener duplication checking (to avoid multiple registrations). diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaAutoFlushEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaAutoFlushEventListener.java similarity index 97% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaAutoFlushEventListener.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaAutoFlushEventListener.java index d95ce64369..8df21999a0 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaAutoFlushEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaAutoFlushEventListener.java @@ -21,7 +21,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.internal.event; +package org.hibernate.jpa.internal.event.core; import java.util.IdentityHashMap; diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaDeleteEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaDeleteEventListener.java similarity index 80% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaDeleteEventListener.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaDeleteEventListener.java index 8c98271cc9..ac24a91bbd 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaDeleteEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaDeleteEventListener.java @@ -21,13 +21,15 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.internal.event; +package org.hibernate.jpa.internal.event.core; 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.internal.event.jpa.CallbackRegistryConsumer; +import org.hibernate.jpa.internal.event.jpa.CallbackRegistry; import org.hibernate.persister.entity.EntityPersister; /** @@ -35,25 +37,25 @@ import org.hibernate.persister.entity.EntityPersister; * * @author Emmanuel Bernard */ -public class JpaDeleteEventListener extends DefaultDeleteEventListener implements CallbackHandlerConsumer { - private EntityCallbackHandler callbackHandler; +public class JpaDeleteEventListener extends DefaultDeleteEventListener implements CallbackRegistryConsumer { + private CallbackRegistry callbackRegistry; - public void setCallbackHandler(EntityCallbackHandler callbackHandler) { - this.callbackHandler = callbackHandler; + public void injectCallbackRegistry(CallbackRegistry callbackRegistry) { + this.callbackRegistry = callbackRegistry; } public JpaDeleteEventListener() { super(); } - public JpaDeleteEventListener(EntityCallbackHandler callbackHandler) { + public JpaDeleteEventListener(CallbackRegistry callbackRegistry) { this(); - this.callbackHandler = callbackHandler; + this.callbackRegistry = callbackRegistry; } @Override protected boolean invokeDeleteLifecycle(EventSource session, Object entity, EntityPersister persister) { - callbackHandler.preRemove( entity ); + callbackRegistry.preRemove( entity ); return super.invokeDeleteLifecycle( session, entity, persister ); } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaFlushEntityEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaFlushEntityEventListener.java similarity index 82% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaFlushEntityEventListener.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaFlushEntityEventListener.java index e7f162684e..386ae9e193 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaFlushEntityEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaFlushEntityEventListener.java @@ -21,13 +21,15 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.internal.event; +package org.hibernate.jpa.internal.event.core; import org.hibernate.SessionFactory; 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.internal.event.jpa.CallbackRegistryConsumer; +import org.hibernate.jpa.internal.event.jpa.CallbackRegistry; import org.hibernate.metadata.ClassMetadata; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.type.Type; @@ -37,20 +39,20 @@ import org.hibernate.type.Type; * * @author Emmanuel Bernard */ -public class JpaFlushEntityEventListener extends DefaultFlushEntityEventListener implements CallbackHandlerConsumer { - private EntityCallbackHandler callbackHandler; +public class JpaFlushEntityEventListener extends DefaultFlushEntityEventListener implements CallbackRegistryConsumer { + private CallbackRegistry callbackRegistry; - public void setCallbackHandler(EntityCallbackHandler callbackHandler) { - this.callbackHandler = callbackHandler; + public void injectCallbackRegistry(CallbackRegistry callbackRegistry) { + this.callbackRegistry = callbackRegistry; } public JpaFlushEntityEventListener() { super(); } - public JpaFlushEntityEventListener(EntityCallbackHandler callbackHandler) { + public JpaFlushEntityEventListener(CallbackRegistry callbackRegistry) { super(); - this.callbackHandler = callbackHandler; + this.callbackRegistry = callbackRegistry; } @Override @@ -62,7 +64,7 @@ public class JpaFlushEntityEventListener extends DefaultFlushEntityEventListener EntityPersister persister) { boolean isDirty = false; if ( entry.getStatus() != Status.DELETED ) { - if ( callbackHandler.preUpdate( entity ) ) { + if ( callbackRegistry.preUpdate( entity ) ) { isDirty = copyState( entity, persister.getPropertyTypes(), values, session.getFactory() ); } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaFlushEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaFlushEventListener.java similarity index 97% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaFlushEventListener.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaFlushEventListener.java index 4ebcdb5d35..b37dfd310d 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaFlushEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaFlushEventListener.java @@ -21,7 +21,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.internal.event; +package org.hibernate.jpa.internal.event.core; import java.util.IdentityHashMap; diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaMergeEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaMergeEventListener.java similarity index 77% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaMergeEventListener.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaMergeEventListener.java index ec7bea6bcd..6d3b847f3f 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaMergeEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaMergeEventListener.java @@ -21,32 +21,34 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.internal.event; +package org.hibernate.jpa.internal.event.core; import java.io.Serializable; import org.hibernate.event.internal.DefaultMergeEventListener; import org.hibernate.event.spi.EventSource; +import org.hibernate.jpa.internal.event.jpa.CallbackRegistryConsumer; +import org.hibernate.jpa.internal.event.jpa.CallbackRegistry; /** * Overrides the LifeCycle OnSave call to call the PrePersist operation * * @author Emmanuel Bernard */ -public class JpaMergeEventListener extends DefaultMergeEventListener implements CallbackHandlerConsumer { - private EntityCallbackHandler callbackHandler; +public class JpaMergeEventListener extends DefaultMergeEventListener implements CallbackRegistryConsumer { + private CallbackRegistry callbackRegistry; - public void setCallbackHandler(EntityCallbackHandler callbackHandler) { - this.callbackHandler = callbackHandler; + public void injectCallbackRegistry(CallbackRegistry callbackRegistry) { + this.callbackRegistry = callbackRegistry; } public JpaMergeEventListener() { super(); } - public JpaMergeEventListener(EntityCallbackHandler callbackHandler) { + public JpaMergeEventListener(CallbackRegistry callbackRegistry) { super(); - this.callbackHandler = callbackHandler; + this.callbackRegistry = callbackRegistry; } @Override @@ -56,7 +58,7 @@ public class JpaMergeEventListener extends DefaultMergeEventListener implements String entityName, Object anything, EventSource source) { - callbackHandler.preCreate( entity ); + callbackRegistry.preCreate( entity ); return super.saveWithRequestedId( entity, requestedId, entityName, anything, source ); } @@ -67,7 +69,7 @@ public class JpaMergeEventListener extends DefaultMergeEventListener implements Object anything, EventSource source, boolean requiresImmediateIdAccess) { - callbackHandler.preCreate( entity ); + callbackRegistry.preCreate( entity ); return super.saveWithGeneratedId( entity, entityName, anything, source, requiresImmediateIdAccess ); } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaPersistEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaPersistEventListener.java similarity index 85% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaPersistEventListener.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaPersistEventListener.java index ccb6235a99..1949c98e0e 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaPersistEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaPersistEventListener.java @@ -21,7 +21,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.internal.event; +package org.hibernate.jpa.internal.event.core; import java.io.Serializable; import java.util.Iterator; @@ -34,6 +34,8 @@ 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.internal.event.jpa.CallbackRegistryConsumer; +import org.hibernate.jpa.internal.event.jpa.CallbackRegistry; import org.hibernate.type.CollectionType; /** @@ -41,23 +43,23 @@ import org.hibernate.type.CollectionType; * * @author Emmanuel Bernard */ -public class JpaPersistEventListener extends DefaultPersistEventListener implements CallbackHandlerConsumer { +public class JpaPersistEventListener extends DefaultPersistEventListener implements CallbackRegistryConsumer { private static final Logger log = Logger.getLogger( JpaPersistEventListener.class ); - private EntityCallbackHandler callbackHandler; + private CallbackRegistry callbackRegistry; @Override - public void setCallbackHandler(EntityCallbackHandler callbackHandler) { - this.callbackHandler = callbackHandler; + public void injectCallbackRegistry(CallbackRegistry callbackRegistry) { + this.callbackRegistry = callbackRegistry; } public JpaPersistEventListener() { super(); } - public JpaPersistEventListener(EntityCallbackHandler callbackHandler) { + public JpaPersistEventListener(CallbackRegistry callbackRegistry) { super(); - this.callbackHandler = callbackHandler; + this.callbackRegistry = callbackRegistry; } @Override @@ -67,7 +69,7 @@ public class JpaPersistEventListener extends DefaultPersistEventListener impleme String entityName, Object anything, EventSource source) { - callbackHandler.preCreate( entity ); + callbackRegistry.preCreate( entity ); return super.saveWithRequestedId( entity, requestedId, entityName, anything, source ); } @@ -78,7 +80,7 @@ public class JpaPersistEventListener extends DefaultPersistEventListener impleme Object anything, EventSource source, boolean requiresImmediateIdAccess) { - callbackHandler.preCreate( entity ); + callbackRegistry.preCreate( entity ); return super.saveWithGeneratedId( entity, entityName, anything, source, requiresImmediateIdAccess ); } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaPersistOnFlushEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaPersistOnFlushEventListener.java similarity index 96% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaPersistOnFlushEventListener.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaPersistOnFlushEventListener.java index 132c4aedb9..f99ee068d1 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaPersistOnFlushEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaPersistOnFlushEventListener.java @@ -21,7 +21,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.internal.event; +package org.hibernate.jpa.internal.event.core; import org.hibernate.engine.spi.CascadingAction; import org.hibernate.engine.spi.CascadingActions; diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaPostDeleteEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaPostDeleteEventListener.java similarity index 73% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaPostDeleteEventListener.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaPostDeleteEventListener.java index b5e13fd965..0309f9b8dc 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaPostDeleteEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaPostDeleteEventListener.java @@ -21,32 +21,34 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.internal.event; +package org.hibernate.jpa.internal.event.core; import org.hibernate.event.spi.PostDeleteEvent; import org.hibernate.event.spi.PostDeleteEventListener; +import org.hibernate.jpa.internal.event.jpa.CallbackRegistryConsumer; +import org.hibernate.jpa.internal.event.jpa.CallbackRegistry; /** * @author Kabir Khan */ -public class JpaPostDeleteEventListener implements PostDeleteEventListener, CallbackHandlerConsumer { - EntityCallbackHandler callbackHandler; +public class JpaPostDeleteEventListener implements PostDeleteEventListener, CallbackRegistryConsumer { + CallbackRegistry callbackRegistry; - public void setCallbackHandler(EntityCallbackHandler callbackHandler) { - this.callbackHandler = callbackHandler; + public void injectCallbackRegistry(CallbackRegistry callbackRegistry) { + this.callbackRegistry = callbackRegistry; } public JpaPostDeleteEventListener() { super(); } - public JpaPostDeleteEventListener(EntityCallbackHandler callbackHandler) { - this.callbackHandler = callbackHandler; + public JpaPostDeleteEventListener(CallbackRegistry callbackRegistry) { + this.callbackRegistry = callbackRegistry; } public void onPostDelete(PostDeleteEvent event) { Object entity = event.getEntity(); - callbackHandler.postRemove( entity ); + callbackRegistry.postRemove( entity ); } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaPostInsertEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaPostInsertEventListener.java similarity index 73% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaPostInsertEventListener.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaPostInsertEventListener.java index 8aa7ad373c..f6b054247c 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaPostInsertEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaPostInsertEventListener.java @@ -21,33 +21,35 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.internal.event; +package org.hibernate.jpa.internal.event.core; import org.hibernate.event.spi.PostInsertEvent; import org.hibernate.event.spi.PostInsertEventListener; +import org.hibernate.jpa.internal.event.jpa.CallbackRegistryConsumer; +import org.hibernate.jpa.internal.event.jpa.CallbackRegistry; /** * @author Kabir Khan */ -public class JpaPostInsertEventListener implements PostInsertEventListener, CallbackHandlerConsumer { - EntityCallbackHandler callbackHandler; +public class JpaPostInsertEventListener implements PostInsertEventListener, CallbackRegistryConsumer { + CallbackRegistry callbackRegistry; @Override - public void setCallbackHandler(EntityCallbackHandler callbackHandler) { - this.callbackHandler = callbackHandler; + public void injectCallbackRegistry(CallbackRegistry callbackRegistry) { + this.callbackRegistry = callbackRegistry; } public JpaPostInsertEventListener() { super(); } - public JpaPostInsertEventListener(EntityCallbackHandler callbackHandler) { - this.callbackHandler = callbackHandler; + public JpaPostInsertEventListener(CallbackRegistry callbackRegistry) { + this.callbackRegistry = callbackRegistry; } @Override public void onPostInsert(PostInsertEvent event) { Object entity = event.getEntity(); - callbackHandler.postCreate( entity ); + callbackRegistry.postCreate( entity ); } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaPostLoadEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaPostLoadEventListener.java similarity index 73% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaPostLoadEventListener.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaPostLoadEventListener.java index 6f10739b80..06fc1fb181 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaPostLoadEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaPostLoadEventListener.java @@ -21,34 +21,36 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.internal.event; +package org.hibernate.jpa.internal.event.core; import org.hibernate.event.spi.PostLoadEvent; import org.hibernate.event.spi.PostLoadEventListener; +import org.hibernate.jpa.internal.event.jpa.CallbackRegistryConsumer; +import org.hibernate.jpa.internal.event.jpa.CallbackRegistry; /** * @author Kabir Khan */ -public class JpaPostLoadEventListener implements PostLoadEventListener, CallbackHandlerConsumer { - EntityCallbackHandler callbackHandler; +public class JpaPostLoadEventListener implements PostLoadEventListener, CallbackRegistryConsumer { + CallbackRegistry callbackRegistry; @Override - public void setCallbackHandler(EntityCallbackHandler callbackHandler) { - this.callbackHandler = callbackHandler; + public void injectCallbackRegistry(CallbackRegistry callbackRegistry) { + this.callbackRegistry = callbackRegistry; } public JpaPostLoadEventListener() { super(); } - public JpaPostLoadEventListener(EntityCallbackHandler callbackHandler) { - this.callbackHandler = callbackHandler; + public JpaPostLoadEventListener(CallbackRegistry callbackRegistry) { + this.callbackRegistry = callbackRegistry; } @Override public void onPostLoad(PostLoadEvent event) { Object entity = event.getEntity(); - callbackHandler.postLoad( entity ); + callbackRegistry.postLoad( entity ); } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaPostUpdateEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaPostUpdateEventListener.java similarity index 86% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaPostUpdateEventListener.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaPostUpdateEventListener.java index 83d88675c7..54e0befc61 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaPostUpdateEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaPostUpdateEventListener.java @@ -21,7 +21,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.internal.event; +package org.hibernate.jpa.internal.event.core; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.Status; @@ -34,6 +34,8 @@ 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.internal.event.jpa.CallbackRegistryConsumer; +import org.hibernate.jpa.internal.event.jpa.CallbackRegistry; /** * Implementation of the post update listeners. @@ -43,23 +45,23 @@ import org.hibernate.event.spi.PostUpdateEventListener; @SuppressWarnings("serial") public class JpaPostUpdateEventListener implements PostUpdateEventListener, - CallbackHandlerConsumer, + CallbackRegistryConsumer, PostCollectionRecreateEventListener, PostCollectionRemoveEventListener, PostCollectionUpdateEventListener { - EntityCallbackHandler callbackHandler; + CallbackRegistry callbackRegistry; @Override - public void setCallbackHandler(EntityCallbackHandler callbackHandler) { - this.callbackHandler = callbackHandler; + public void injectCallbackRegistry(CallbackRegistry callbackRegistry) { + this.callbackRegistry = callbackRegistry; } public JpaPostUpdateEventListener() { super(); } - public JpaPostUpdateEventListener(EntityCallbackHandler callbackHandler) { - this.callbackHandler = callbackHandler; + public JpaPostUpdateEventListener(CallbackRegistry callbackRegistry) { + this.callbackRegistry = callbackRegistry; } @Override @@ -74,7 +76,7 @@ public class JpaPostUpdateEventListener .getEntityEntries().get(entity); // mimic the preUpdate filter if ( Status.DELETED != entry.getStatus()) { - callbackHandler.postUpdate(entity); + callbackRegistry.postUpdate(entity); } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaSaveEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaSaveEventListener.java similarity index 77% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaSaveEventListener.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaSaveEventListener.java index 8f9c7b145c..a0c3e832c9 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaSaveEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaSaveEventListener.java @@ -21,32 +21,34 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.internal.event; +package org.hibernate.jpa.internal.event.core; import java.io.Serializable; import org.hibernate.event.internal.DefaultSaveEventListener; import org.hibernate.event.spi.EventSource; +import org.hibernate.jpa.internal.event.jpa.CallbackRegistryConsumer; +import org.hibernate.jpa.internal.event.jpa.CallbackRegistry; /** * Overrides the LifeCycle OnSave call to call the PrePersist operation * * @author Emmanuel Bernard */ -public class JpaSaveEventListener extends DefaultSaveEventListener implements CallbackHandlerConsumer { - private EntityCallbackHandler callbackHandler; +public class JpaSaveEventListener extends DefaultSaveEventListener implements CallbackRegistryConsumer { + private CallbackRegistry callbackRegistry; - public void setCallbackHandler(EntityCallbackHandler callbackHandler) { - this.callbackHandler = callbackHandler; + public void injectCallbackRegistry(CallbackRegistry callbackRegistry) { + this.callbackRegistry = callbackRegistry; } public JpaSaveEventListener() { super(); } - public JpaSaveEventListener(EntityCallbackHandler callbackHandler) { + public JpaSaveEventListener(CallbackRegistry callbackRegistry) { super(); - this.callbackHandler = callbackHandler; + this.callbackRegistry = callbackRegistry; } @Override @@ -56,7 +58,7 @@ public class JpaSaveEventListener extends DefaultSaveEventListener implements Ca String entityName, Object anything, EventSource source) { - callbackHandler.preCreate( entity ); + callbackRegistry.preCreate( entity ); return super.saveWithRequestedId( entity, requestedId, entityName, anything, source ); } @@ -67,7 +69,7 @@ public class JpaSaveEventListener extends DefaultSaveEventListener implements Ca Object anything, EventSource source, boolean requiresImmediateIdAccess) { - callbackHandler.preCreate( entity ); + callbackRegistry.preCreate( entity ); return super.saveWithGeneratedId( entity, entityName, anything, source, requiresImmediateIdAccess ); } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaSaveOrUpdateEventListener.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaSaveOrUpdateEventListener.java similarity index 77% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaSaveOrUpdateEventListener.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaSaveOrUpdateEventListener.java index 6675764c4c..108c930f91 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/JpaSaveOrUpdateEventListener.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/JpaSaveOrUpdateEventListener.java @@ -21,32 +21,34 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.internal.event; +package org.hibernate.jpa.internal.event.core; import java.io.Serializable; import org.hibernate.event.internal.DefaultSaveOrUpdateEventListener; import org.hibernate.event.spi.EventSource; +import org.hibernate.jpa.internal.event.jpa.CallbackRegistryConsumer; +import org.hibernate.jpa.internal.event.jpa.CallbackRegistry; /** * Overrides the LifeCycle OnSave call to call the PrePersist operation * * @author Emmanuel Bernard */ -public class JpaSaveOrUpdateEventListener extends DefaultSaveOrUpdateEventListener implements CallbackHandlerConsumer { - private EntityCallbackHandler callbackHandler; +public class JpaSaveOrUpdateEventListener extends DefaultSaveOrUpdateEventListener implements CallbackRegistryConsumer { + private CallbackRegistry callbackRegistry; - public void setCallbackHandler(EntityCallbackHandler callbackHandler) { - this.callbackHandler = callbackHandler; + public void injectCallbackRegistry(CallbackRegistry callbackRegistry) { + this.callbackRegistry = callbackRegistry; } public JpaSaveOrUpdateEventListener() { super(); } - public JpaSaveOrUpdateEventListener(EntityCallbackHandler callbackHandler) { + public JpaSaveOrUpdateEventListener(CallbackRegistry callbackRegistry) { super(); - this.callbackHandler = callbackHandler; + this.callbackRegistry = callbackRegistry; } @Override @@ -56,7 +58,7 @@ public class JpaSaveOrUpdateEventListener extends DefaultSaveOrUpdateEventListen String entityName, Object anything, EventSource source) { - callbackHandler.preCreate( entity ); + callbackRegistry.preCreate( entity ); return super.saveWithRequestedId( entity, requestedId, entityName, anything, source ); } @@ -67,7 +69,7 @@ public class JpaSaveOrUpdateEventListener extends DefaultSaveOrUpdateEventListen Object anything, EventSource source, boolean requiresImmediateIdAccess) { - callbackHandler.preCreate( entity ); + callbackRegistry.preCreate( entity ); return super.saveWithGeneratedId( entity, entityName, anything, source, requiresImmediateIdAccess ); } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/package-info.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/package-info.java new file mode 100644 index 0000000000..e7f13fdad3 --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/core/package-info.java @@ -0,0 +1,32 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.internal.event.core; + +/** + * Hibernate EntityManager specific implementations of Hibernate event listeners. Generally the listeners + * here either: + */ \ No newline at end of file diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/BeanManagerListenerFactory.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/BeanManagerListenerFactory.java new file mode 100644 index 0000000000..f9e2724214 --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/BeanManagerListenerFactory.java @@ -0,0 +1,87 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.internal.event.jpa; + +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 java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 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 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/internal/event/jpa/Callback.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/Callback.java new file mode 100644 index 0000000000..f7520a42bc --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/Callback.java @@ -0,0 +1,41 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2009-2011, 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.jpa.internal.event.jpa; + +import java.io.Serializable; + +/** + * Represents a JPA event callback. + * + * @author Kabir Khan + * @author Steve Ebersole + */ +public interface Callback extends Serializable { + /** + * Contract for performing the callback + * + * @param entity Reference to the entity for which the callback is triggered. + */ + public abstract void performCallback(Object entity); +} diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/CallbackProcessor.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/CallbackProcessor.java new file mode 100644 index 0000000000..ef01fefbc5 --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/CallbackProcessor.java @@ -0,0 +1,58 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.internal.event.jpa; + +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; + +/** + * Delegate for interpreting, parsing and processing callbacks + * + * @author Steve Ebersole + */ +public interface CallbackProcessor { + public static final Class[] CALLBACK_ANNOTATION_CLASSES = new Class[] { + PreUpdate.class, PostUpdate.class, + PrePersist.class, PostPersist.class, + PreRemove.class, PostRemove.class, + PostLoad.class + }; + + /** + * Ugh, Object to account for Configuration/Metamodel split. Should eventually be EntityBinding from + * metamodel code base. Currently each Integrator method passes in different type and each impl + * interprets differently. + * + * @param entityObject + * @param registry + */ + public void processCallbacksForEntity(Object entityObject, CallbackRegistry registry); + + public void release(); +} diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/CallbackProcessorImpl.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/CallbackProcessorImpl.java new file mode 100644 index 0000000000..0f69e5ed46 --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/CallbackProcessorImpl.java @@ -0,0 +1,162 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.internal.event.jpa; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import org.jboss.logging.Logger; + +import org.hibernate.MappingException; +import org.hibernate.metamodel.binding.EntityBinding; +import org.hibernate.metamodel.source.MetadataImplementor; +import org.hibernate.metamodel.source.binder.JpaCallbackClass; +import org.hibernate.service.classloading.spi.ClassLoaderService; +import org.hibernate.service.classloading.spi.ClassLoadingException; +import org.hibernate.service.spi.SessionFactoryServiceRegistry; + +/** + * @author Steve Ebersole + */ +public class CallbackProcessorImpl implements CallbackProcessor { + private static final Logger log = Logger.getLogger( CallbackProcessorImpl.class ); + + private final ListenerFactory jpaListenerFactory; + private final MetadataImplementor metadata; + + private final ClassLoaderService classLoaderService; + + public CallbackProcessorImpl( + ListenerFactory jpaListenerFactory, + MetadataImplementor metadata, + SessionFactoryServiceRegistry serviceRegistry) { + this.jpaListenerFactory = jpaListenerFactory; + this.metadata = metadata; + this.classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); + } + + @Override + public void processCallbacksForEntity(Object entityObject, CallbackRegistry callbackRegistry) { + final EntityBinding entityBinding = (EntityBinding) entityObject; + final String entityClassName = entityBinding.getEntity().getClassName(); + if ( entityClassName == null ) { + return; + } + + try { + final Class entityClass = classLoaderService.classForName( entityClassName ); + for ( Class annotationClass : CALLBACK_ANNOTATION_CLASSES ) { + callbackRegistry.addEntityCallbacks( + entityClass, + annotationClass, + collectCallbacks( entityBinding, entityClass, annotationClass ) + ); + } + } + catch (ClassLoadingException e) { + throw new MappingException( "entity class not found: " + entityClassName, e ); + } + } + + private Callback[] collectCallbacks(EntityBinding entityBinding, Class entityClass, Class annotationClass) { + final List callbacks = new ArrayList(); + for ( JpaCallbackClass jpaCallbackClass : entityBinding.getJpaCallbackClasses() ) { + final Class listenerClass = classLoaderService.classForName( jpaCallbackClass.getName() ); + final String methodName = jpaCallbackClass.getCallbackMethod( annotationClass ); + + log.debugf( + "Adding $s.%s as %s callback for entity %s", + listenerClass.getName(), + methodName, + annotationClass.getName(), + entityClass.getName() + ); + + final Callback callback = jpaCallbackClass.isListener() + ? createListenerCallback( listenerClass, entityClass, methodName ) + : createBeanCallback( listenerClass, methodName ); + assert callback != null; + callbacks.add(callback); + } + return callbacks.toArray(new Callback[callbacks.size()]); + } + + private Callback createListenerCallback( + Class listenerClass, + Class entityClass, + String methodName ) { + final Class callbackSuperclass = listenerClass.getSuperclass(); + if ( callbackSuperclass != null ) { + Callback callback = createListenerCallback( entityClass, callbackSuperclass, methodName ); + if ( callback != null ) { + return callback; + } + } + + final Object listenerInstance = jpaListenerFactory.buildListener( listenerClass ); + for ( Method method : listenerClass.getDeclaredMethods() ) { + if ( !method.getName().equals(methodName) ) { + continue; + } + + final Class[] argTypes = method.getParameterTypes(); + if (argTypes.length != 1) { + continue; + } + + final Class argType = argTypes[0]; + if (argType != Object.class && argType != entityClass) { + continue; + } + if (!method.isAccessible()) { + method.setAccessible( true ); + } + + return new ListenerCallback( listenerInstance, method ); + } + return null; + } + + private Callback createBeanCallback( Class callbackClass, + String methodName ) { + Class callbackSuperclass = callbackClass.getSuperclass(); + if (callbackSuperclass != null) { + Callback callback = createBeanCallback(callbackSuperclass, methodName); + if (callback != null) return callback; + } + for (Method method : callbackClass.getDeclaredMethods()) { + if (!method.getName().equals(methodName)) continue; + if (method.getParameterTypes().length != 0) continue; + if (!method.isAccessible()) method.setAccessible(true); + return new EntityCallback(method); + } + return null; + } + + @Override + public void release() { + //To change body of implemented methods use File | Settings | File Templates. + } +} diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/EntityCallbackHandler.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/CallbackRegistry.java similarity index 56% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/EntityCallbackHandler.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/CallbackRegistry.java index 8b5c42b681..77e0a442f8 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/EntityCallbackHandler.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/CallbackRegistry.java @@ -21,10 +21,9 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.internal.event; +package org.hibernate.jpa.internal.event.jpa; -import java.io.Serializable; -import java.util.HashMap; +import javax.persistence.PersistenceException; import javax.persistence.PostLoad; import javax.persistence.PostPersist; import javax.persistence.PostRemove; @@ -32,19 +31,17 @@ import javax.persistence.PostUpdate; import javax.persistence.PrePersist; import javax.persistence.PreRemove; import javax.persistence.PreUpdate; - -import org.hibernate.annotations.common.reflection.ReflectionManager; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.metamodel.binding.EntityBinding; -import org.hibernate.service.classloading.spi.ClassLoaderService; +import java.io.Serializable; +import java.util.HashMap; /** * Keep track of all lifecycle callbacks and listeners for a given persistence unit * * @author Kabir Khan + * @author Steve Ebersole */ @SuppressWarnings({"unchecked", "serial"}) -public class EntityCallbackHandler implements Serializable { +public class CallbackRegistry implements Serializable { private HashMap preCreates = new HashMap(); private HashMap postCreates = new HashMap(); private HashMap preRemoves = new HashMap(); @@ -53,28 +50,6 @@ public class EntityCallbackHandler implements Serializable { private HashMap postUpdates = new HashMap(); private HashMap postLoads = new HashMap(); - public void add(XClass entity, ReflectionManager reflectionManager) { - addCallback( entity, preCreates, PrePersist.class, reflectionManager ); - addCallback( entity, postCreates, PostPersist.class, reflectionManager ); - addCallback( entity, preRemoves, PreRemove.class, reflectionManager ); - addCallback( entity, postRemoves, PostRemove.class, reflectionManager ); - addCallback( entity, preUpdates, PreUpdate.class, reflectionManager ); - addCallback( entity, postUpdates, PostUpdate.class, reflectionManager ); - addCallback( entity, postLoads, PostLoad.class, reflectionManager ); - } - - public void add( Class entity, - ClassLoaderService classLoaderService, - EntityBinding binding ) { - addCallback( entity, preCreates, PrePersist.class, classLoaderService, binding ); - addCallback( entity, postCreates, PostPersist.class, classLoaderService, binding ); - addCallback( entity, preRemoves, PreRemove.class, classLoaderService, binding ); - addCallback( entity, postRemoves, PostRemove.class, classLoaderService, binding ); - addCallback( entity, preUpdates, PreUpdate.class, classLoaderService, binding ); - addCallback( entity, postUpdates, PostUpdate.class, classLoaderService, binding ); - addCallback( entity, postLoads, PostLoad.class, classLoaderService, binding ); - } - public boolean preCreate(Object bean) { return callback( preCreates.get( bean.getClass() ), bean ); } @@ -103,11 +78,10 @@ public class EntityCallbackHandler implements Serializable { return callback( postLoads.get( bean.getClass() ), bean ); } - private boolean callback(Callback[] callbacks, Object bean) { if ( callbacks != null && callbacks.length != 0 ) { for ( Callback callback : callbacks ) { - callback.invoke( bean ); + callback.performCallback( bean ); } return true; } @@ -116,19 +90,56 @@ public class EntityCallbackHandler implements Serializable { } } - private void addCallback( - XClass entity, HashMap map, Class annotation, ReflectionManager reflectionManager - ) { - Callback[] callbacks = null; - callbacks = CallbackResolver.resolveCallback( entity, annotation, reflectionManager ); - map.put( reflectionManager.toClass( entity ), callbacks ); + /* package */ 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 void addCallback( Class entity, - HashMap map, - Class annotation, - ClassLoaderService classLoaderService, - EntityBinding binding ) { - map.put(entity, CallbackResolver.resolveCallbacks(entity, annotation, classLoaderService, binding)); - } + private HashMap determineAppropriateCallbackMap(Class annotationClass) { + if ( PrePersist.class.equals( annotationClass ) ) { + return preCreates; + } + + if ( PostPersist.class.equals( annotationClass ) ) { + return postCreates; + } + + if ( PreRemove.class.equals( annotationClass ) ) { + return preRemoves; + } + + if ( PostRemove.class.equals( annotationClass ) ) { + return postRemoves; + } + + if ( PreUpdate.class.equals( annotationClass ) ) { + return preUpdates; + } + + if ( PostUpdate.class.equals( annotationClass ) ) { + return postUpdates; + } + + if ( PostLoad.class.equals( annotationClass ) ) { + return postLoads; + } + + throw new PersistenceException( "Unrecognized JPA callback annotation [" + annotationClass.getName() + "]" ); + } + + public void release() { + preCreates.clear(); + postCreates.clear(); + + preRemoves.clear(); + postRemoves.clear(); + + preUpdates.clear(); + postUpdates.clear(); + + postLoads.clear(); + } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/CallbackRegistryConsumer.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/CallbackRegistryConsumer.java new file mode 100644 index 0000000000..4175ee85ae --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/CallbackRegistryConsumer.java @@ -0,0 +1,41 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2009-2011, 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.jpa.internal.event.jpa; + +import org.hibernate.jpa.internal.event.core.HibernateEntityManagerEventListener; + +/** + * Contract for injecting the registry of Callbacks into event listeners. + * + * @author Emmanuel Bernard + * @author Steve Ebersole + */ +public interface CallbackRegistryConsumer extends HibernateEntityManagerEventListener { + /** + * Injection of the CallbackRegistry + * + * @param callbackRegistry The CallbackRegistry + */ + public void injectCallbackRegistry(CallbackRegistry callbackRegistry); +} diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/BeanCallback.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/EntityCallback.java similarity index 80% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/BeanCallback.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/EntityCallback.java index 445aadcb37..bbf526a916 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/BeanCallback.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/EntityCallback.java @@ -21,22 +21,28 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.internal.event; +package org.hibernate.jpa.internal.event.jpa; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** + * Represents a JPA callback on the entity itself + * * @author Kabir Khan + * @author Steve Ebersole */ -public class BeanCallback extends Callback { - public BeanCallback(Method callbackMethod) { - super( callbackMethod ); +public class EntityCallback implements Callback { + private Method callbackMethod; + + public EntityCallback(Method callbackMethod) { + this.callbackMethod = callbackMethod; } - public void invoke(Object bean) { + @Override + public void performCallback(Object entity) { try { - callbackMethod.invoke( bean, new Object[0] ); + callbackMethod.invoke( entity ); } catch (InvocationTargetException e) { //keep runtime exceptions as is diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/CallbackResolver.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/LegacyCallbackProcessor.java similarity index 58% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/CallbackResolver.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/LegacyCallbackProcessor.java index 28905a1f75..1a4d5cd0dd 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/CallbackResolver.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/LegacyCallbackProcessor.java @@ -1,7 +1,7 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright (c) 2009-2011, Red Hat Inc. or third-party contributors as + * Copyright (c) 2012, 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. @@ -21,7 +21,21 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.internal.event; +package org.hibernate.jpa.internal.event.jpa; + +import javax.persistence.Entity; +import javax.persistence.EntityListeners; +import javax.persistence.ExcludeDefaultListeners; +import javax.persistence.ExcludeSuperclassListeners; +import javax.persistence.MappedSuperclass; +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 java.lang.annotation.Annotation; import java.lang.annotation.ElementType; @@ -29,48 +43,46 @@ import java.lang.annotation.Target; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.ExcludeDefaultListeners; -import javax.persistence.ExcludeSuperclassListeners; -import javax.persistence.MappedSuperclass; -import javax.persistence.PersistenceException; import org.jboss.logging.Logger; +import org.hibernate.MappingException; 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.internal.EntityManagerMessageLogger; -import org.hibernate.metamodel.binding.EntityBinding; -import org.hibernate.metamodel.source.binder.JpaCallbackClass; -import org.hibernate.service.classloading.spi.ClassLoaderService; /** * @author Kabir Khan + * @author Steve Ebersole */ -public final class CallbackResolver { +public class LegacyCallbackProcessor implements CallbackProcessor { + private static final Logger log = Logger.getLogger( LegacyCallbackProcessor.class ); - private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(EntityManagerMessageLogger.class, - CallbackResolver.class.getName()); + private final ListenerFactory jpaListenerFactory; + private final ReflectionManager reflectionManager; - private static boolean useAnnotationAnnotatedByListener; + public LegacyCallbackProcessor(ListenerFactory jpaListenerFactory, ReflectionManager reflectionManager) { + this.jpaListenerFactory = jpaListenerFactory; + this.reflectionManager = reflectionManager; + } - static { - //check whether reading annotations of annotations is useful or not - useAnnotationAnnotatedByListener = false; - Target target = EntityListeners.class.getAnnotation( Target.class ); - if ( target != null ) { - for ( ElementType type : target.value() ) { - if ( type.equals( ElementType.ANNOTATION_TYPE ) ) useAnnotationAnnotatedByListener = true; + @Override + public void processCallbacksForEntity(Object entityObject, CallbackRegistry callbackRegistry) { + final String entityClassName = (String) entityObject; + try { + final XClass entityXClass = reflectionManager.classForName( entityClassName, this.getClass() ); + final Class entityClass = reflectionManager.toClass( entityXClass ); + for ( Class annotationClass : CALLBACK_ANNOTATION_CLASSES ) { + final Callback[] callbacks = resolveCallbacks( entityXClass, annotationClass, reflectionManager ); + callbackRegistry.addEntityCallbacks( entityClass, annotationClass, callbacks ); } } + catch (ClassNotFoundException e) { + throw new MappingException( "entity class not found: " + entityClassName, e ); + } } - private CallbackResolver() { - } - - public static Callback[] resolveCallback(XClass beanClass, Class annotation, ReflectionManager reflectionManager) { + public Callback[] resolveCallbacks(XClass beanClass, Class annotation, ReflectionManager reflectionManager) { List callbacks = new ArrayList(); List callbacksMethodNames = new ArrayList(); //used to track overridden methods List orderedListeners = new ArrayList(); @@ -89,7 +101,7 @@ public final class CallbackResolver { if ( ! callbacksMethodNames.contains( methodName ) ) { //overridden method, remove the superclass overridden method if ( callback == null ) { - callback = new BeanCallback( method ); + callback = new EntityCallback( method ); Class returnType = method.getReturnType(); Class[] args = method.getParameterTypes(); if ( returnType != Void.TYPE || args.length != 0 ) { @@ -98,11 +110,11 @@ public final class CallbackResolver { .getName() + " - " + xMethod ); } - if (!method.isAccessible()) method.setAccessible(true); - LOG.debugf("Adding %s as %s callback for entity %s", - methodName, - annotation.getSimpleName(), - beanClass.getName()); + if (!method.isAccessible()) method.setAccessible(true); + log.debugf("Adding %s as %s callback for entity %s", + methodName, + annotation.getSimpleName(), + beanClass.getName()); callbacks.add( 0, callback ); //superclass first callbacksMethodNames.add( 0, methodName ); } @@ -158,21 +170,8 @@ public final class CallbackResolver { if ( ! callbacksMethodNames.contains( methodName ) ) { //overridden method, remove the superclass overridden method if ( callback == null ) { - try { - callback = new ListenerCallback( method, listener.newInstance() ); - } - catch (IllegalAccessException e) { - throw new PersistenceException( - "Unable to create instance of " + listener.getName() - + " as a listener of beanClass", e - ); - } - catch (InstantiationException e) { - throw new PersistenceException( - "Unable to create instance of " + listener.getName() - + " as a listener of beanClass", e - ); - } + callback = new ListenerCallback( jpaListenerFactory.buildListener( listener ), method ); + Class returnType = method.getReturnType(); Class[] args = method.getParameterTypes(); if ( returnType != Void.TYPE || args.length != 1 ) { @@ -181,11 +180,11 @@ public final class CallbackResolver { .getName() + " - " + method ); } - if (!method.isAccessible()) method.setAccessible(true); - LOG.debugf("Adding %s as %s callback for entity %s", - methodName, - annotation.getSimpleName(), - beanClass.getName()); + if (!method.isAccessible()) method.setAccessible(true); + log.debugf("Adding %s as %s callback for entity %s", + methodName, + annotation.getSimpleName(), + beanClass.getName()); callbacks.add( 0, callback ); // listeners first } else { @@ -203,61 +202,18 @@ public final class CallbackResolver { return callbacks.toArray( new Callback[ callbacks.size() ] ); } - public static Callback[] resolveCallbacks( Class entityClass, - Class callbackClass, - ClassLoaderService classLoaderService, - EntityBinding binding ) { - List callbacks = new ArrayList(); - for (JpaCallbackClass jpaCallbackClass : binding.getJpaCallbackClasses()) { - Object listener = classLoaderService.classForName(jpaCallbackClass.getName()); - String methodName = jpaCallbackClass.getCallbackMethod( callbackClass ); - Callback callback = jpaCallbackClass.isListener() ? - createListenerCallback(entityClass, callbackClass, listener, methodName) : - createBeanCallback(callbackClass, methodName); - LOG.debugf("Adding %s as %s callback for entity %s", methodName, callbackClass.getName(), - entityClass.getName()); - assert callback != null; - callbacks.add(callback); - } - return callbacks.toArray(new Callback[callbacks.size()]); - } + private static boolean useAnnotationAnnotatedByListener; - private static Callback createListenerCallback( Class entityClass, - Class callbackClass, - Object listener, - String methodName ) { - Class callbackSuperclass = callbackClass.getSuperclass(); - if (callbackSuperclass != null) { - Callback callback = createListenerCallback(entityClass, callbackSuperclass, listener, methodName); - if (callback != null) return callback; - } - for (Method method : callbackClass.getDeclaredMethods()) { - if (!method.getName().equals(methodName)) continue; - Class[] argTypes = method.getParameterTypes(); - if (argTypes.length != 1) continue; - Class argType = argTypes[0]; - if (argType != Object.class && argType != entityClass) continue; - if (!method.isAccessible()) method.setAccessible(true); - return new ListenerCallback(method, listener); - } - return null; - } - - private static Callback createBeanCallback( Class callbackClass, - String methodName ) { - Class callbackSuperclass = callbackClass.getSuperclass(); - if (callbackSuperclass != null) { - Callback callback = createBeanCallback(callbackSuperclass, methodName); - if (callback != null) return callback; - } - for (Method method : callbackClass.getDeclaredMethods()) { - if (!method.getName().equals(methodName)) continue; - if (method.getParameterTypes().length != 0) continue; - if (!method.isAccessible()) method.setAccessible(true); - return new BeanCallback(method); - } - return null; - } + static { + //check whether reading annotations of annotations is useful or not + useAnnotationAnnotatedByListener = false; + Target target = EntityListeners.class.getAnnotation( Target.class ); + if ( target != null ) { + for ( ElementType type : target.value() ) { + if ( type.equals( ElementType.ANNOTATION_TYPE ) ) useAnnotationAnnotatedByListener = true; + } + } + } private static void getListeners(XClass currentClazz, List orderedListeners) { EntityListeners entityListeners = currentClazz.getAnnotation( EntityListeners.class ); @@ -282,4 +238,9 @@ public final class CallbackResolver { } } } + + @Override + public void release() { + // nothing to do here + } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/ListenerCallback.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/ListenerCallback.java similarity index 57% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/ListenerCallback.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/ListenerCallback.java index 0796d3f269..a0b2414238 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/ListenerCallback.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/ListenerCallback.java @@ -21,31 +21,30 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.internal.event; +package org.hibernate.jpa.internal.event.jpa; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import org.hibernate.internal.util.ReflectHelper; - /** + * Represents a JPA callback using a dedicated listener + * * @author Kabir Khan + * @author Steve Ebersole */ -public class ListenerCallback extends Callback { - protected transient Object listener; +public class ListenerCallback implements Callback { + private final Method callbackMethod; + private final Object listenerInstance; - public ListenerCallback(Method callbackMethod, Object listener) { - super( callbackMethod ); - this.listener = listener; + public ListenerCallback(Object listenerInstance, Method callbackMethod) { + this.listenerInstance = listenerInstance; + this.callbackMethod = callbackMethod; } @Override - public void invoke(Object bean) { + public void performCallback(Object entity) { try { - callbackMethod.invoke( listener, new Object[]{bean} ); + callbackMethod.invoke( listenerInstance, entity ); } catch (InvocationTargetException e) { //keep runtime exceptions as is @@ -60,23 +59,4 @@ public class ListenerCallback extends Callback { throw new RuntimeException( e ); } } - - private void writeObject(ObjectOutputStream oos) throws IOException { - oos.defaultWriteObject(); - oos.writeObject( listener.getClass().getName() ); - } - - private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { - ois.defaultReadObject(); - String listenerClass = (String) ois.readObject(); - try { - listener = ReflectHelper.classForName( listenerClass, this.getClass() ).newInstance(); - } - catch (InstantiationException e) { - throw new ClassNotFoundException( "Unable to load class:" + listenerClass, e ); - } - catch (IllegalAccessException e) { - throw new ClassNotFoundException( "Unable to load class:" + listenerClass, e ); - } - } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/ListenerFactory.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/ListenerFactory.java new file mode 100644 index 0000000000..f2622a6976 --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/ListenerFactory.java @@ -0,0 +1,35 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.internal.event.jpa; + +/** + * Factory for building instances user-specified event listeners. + * + * @author Steve Ebersole + */ +public interface ListenerFactory { + public T buildListener(Class listenerClass); + + public void release(); +} diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/StandardListenerFactory.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/StandardListenerFactory.java new file mode 100644 index 0000000000..c0769adb0e --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/StandardListenerFactory.java @@ -0,0 +1,62 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.internal.event.jpa; + +import javax.persistence.PersistenceException; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Standard implementation of the ListenerFactory contract using simple instantiation. Listener instances + * are kept in a map keyed by Class to achieve singleton-ness. + * + * @author Steve Ebersole + */ +public class StandardListenerFactory implements ListenerFactory { + private Map listenerInstances = new ConcurrentHashMap(); + + @Override + @SuppressWarnings("unchecked") + public T buildListener(Class listenerClass) { + Object listenerInstance = listenerInstances.get( listenerClass ); + if ( listenerInstance == null ) { + try { + listenerInstance = listenerClass.newInstance(); + } + catch (Exception e) { + throw new PersistenceException( + "Unable to create instance of " + listenerClass.getName() + " as a JPA callback listener", + e + ); + } + listenerInstances.put( listenerClass, listenerInstance ); + } + return (T) listenerInstance; + } + + @Override + public void release() { + listenerInstances.clear(); + } +} diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/CallbackHandlerConsumer.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/package-info.java similarity index 76% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/CallbackHandlerConsumer.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/package-info.java index 420435bea4..69b0bdcf4b 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/CallbackHandlerConsumer.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/event/jpa/package-info.java @@ -1,7 +1,7 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright (c) 2009-2011, Red Hat Inc. or third-party contributors as + * Copyright (c) 2012, 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. @@ -21,11 +21,8 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.internal.event; +package org.hibernate.jpa.internal.event.jpa; /** - * @author Emmanuel Bernard - */ -public interface CallbackHandlerConsumer extends HibernateEntityManagerEventListener { - void setCallbackHandler(EntityCallbackHandler callbackHandler); -} + * Classes for integrating with JPA event callbacks + */ \ No newline at end of file diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/BaseEntityManagerFunctionalTestCase.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/BaseEntityManagerFunctionalTestCase.java index 62d3a0ef60..27df78bada 100644 --- a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/BaseEntityManagerFunctionalTestCase.java +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/BaseEntityManagerFunctionalTestCase.java @@ -40,7 +40,7 @@ import org.jboss.logging.Logger; import org.hibernate.cfg.Environment; import org.hibernate.dialect.Dialect; -import org.hibernate.ejb.AvailableSettings; +import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.internal.EntityManagerFactoryImpl; import org.hibernate.internal.util.StringHelper; import org.hibernate.jpa.HibernatePersistenceProvider; diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/cdi/BaseCDIIntegrationTest.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/cdi/BaseCDIIntegrationTest.java new file mode 100644 index 0000000000..6d134fe9ce --- /dev/null +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/cdi/BaseCDIIntegrationTest.java @@ -0,0 +1,66 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.test.cdi; + +import javax.enterprise.inject.spi.BeanManager; +import java.util.Map; + +import org.jboss.arquillian.container.weld.ee.embedded_1_1.mock.TestContainer; +import org.jboss.weld.bootstrap.api.Environments; + +import org.hibernate.jpa.AvailableSettings; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +/** + * @author Steve Ebersole + */ +public abstract class BaseCDIIntegrationTest extends BaseEntityManagerFunctionalTestCase { + private TestContainer testContainer; + + @Override + @SuppressWarnings("unchecked") + protected void addConfigOptions(Map options) { + super.addConfigOptions( options ); + + testContainer = new TestContainer( getCdiBeans() ); + testContainer.getBootstrap().startContainer( Environments.SE, testContainer.getDeployment() ); + testContainer.getBootstrap().startInitialization(); + testContainer.getBootstrap().deployBeans(); + testContainer.getBootstrap().validateBeans().endInitialization(); + options.put( AvailableSettings.CDI_BEAN_MANAGER, getBeanManager() ); + } + + protected BeanManager getBeanManager() { + return testContainer.getBeanManager( testContainer.getDeployment().getBeanDeploymentArchives().iterator().next() ); + } + + public abstract Class[] getCdiBeans(); + + @Override + public void releaseResources() { + super.releaseResources(); // closes the EMF + + testContainer.stopContainer(); + } +} diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/cdi/BasicCDITest.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/cdi/BasicCDITest.java new file mode 100644 index 0000000000..a755cb2982 --- /dev/null +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/cdi/BasicCDITest.java @@ -0,0 +1,166 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.test.cdi; + +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.inject.spi.AnnotatedType; +import javax.enterprise.inject.spi.InjectionTarget; +import javax.inject.Inject; +import javax.persistence.Entity; +import javax.persistence.EntityListeners; +import javax.persistence.EntityManager; +import javax.persistence.Id; +import javax.persistence.PrePersist; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * @author Steve Ebersole + */ +public class BasicCDITest extends BaseCDIIntegrationTest { + private static int count; + + @Override + public Class[] getCdiBeans() { + return new Class[] { EventQueue.class }; + } + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { MyEntity.class }; + } + + @Test + @SuppressWarnings("unchecked") + public void testIt() { + count = 0; + + EntityManager em = getOrCreateEntityManager(); + em.getTransaction().begin(); + em.persist( new MyEntity( 1 ) ); + em.getTransaction().commit(); + em.close(); + + assertEquals( 1, count ); + + em = getOrCreateEntityManager(); + em.getTransaction().begin(); + em.remove( em.getReference( MyEntity.class, 1 ) ); + em.getTransaction().commit(); + em.close(); + } + + @Entity + @EntityListeners( Monitor.class ) + public static class MyEntity { + private Integer id; + private String name; + + public MyEntity() { + } + + public MyEntity(Integer id) { + this.id = id; + } + + @Id + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + public static class EventQueue { + private List events; + + public void addEvent(Event anEvent) { + if ( events == null ) { + events = new ArrayList(); + } + events.add( anEvent ); + } + } + + public static class Event { + private final String who; + private final String what; + private final String when; + + public Event(String who, String what, String when) { + this.who = who; + this.what = what; + this.when = when; + } + + public String getWho() { + return who; + } + + public String getWhat() { + return what; + } + + public String getWhen() { + return when; + } + } + + public static class Monitor { + private final EventQueue eventQueue; + + @Inject + public Monitor(EventQueue eventQueue) { + this.eventQueue = eventQueue; + } + + @PrePersist + public void onCreate(Object entity) { + eventQueue.addEvent( + new Event( entity.toString(), "created", now() ) + ); + count++; + } + + private String now() { + return new SimpleDateFormat().format( new Date() ); + } + } +}