HHH-10477 - Setting to allow delayed access to CDI
This commit is contained in:
parent
7f9fd50e26
commit
f3d98cb4ef
|
@ -33,6 +33,10 @@ dependencies {
|
||||||
testCompile( libraries.validation )
|
testCompile( libraries.validation )
|
||||||
testCompile( "org.jboss.weld:weld-core:2.0.0.Beta6" )
|
testCompile( "org.jboss.weld:weld-core:2.0.0.Beta6" )
|
||||||
testCompile( "org.jboss.weld.arquillian.container:arquillian-weld-ee-embedded-1.1:1.1.2.Final" )
|
testCompile( "org.jboss.weld.arquillian.container:arquillian-weld-ee-embedded-1.1:1.1.2.Final" )
|
||||||
|
testCompile( "javax.enterprise:cdi-api:1.1-PFD" ) {
|
||||||
|
// we need to force it to make sure we influence the one coming from arquillian
|
||||||
|
force=true
|
||||||
|
}
|
||||||
testCompile( libraries.mockito )
|
testCompile( libraries.mockito )
|
||||||
|
|
||||||
testRuntime( libraries.validator )
|
testRuntime( libraries.validator )
|
||||||
|
|
|
@ -555,4 +555,12 @@ public interface AvailableSettings {
|
||||||
* Used to pass along the name of the persistence unit.
|
* Used to pass along the name of the persistence unit.
|
||||||
*/
|
*/
|
||||||
String PERSISTENCE_UNIT_NAME = "hibernate.ejb.persistenceUnitName";
|
String PERSISTENCE_UNIT_NAME = "hibernate.ejb.persistenceUnitName";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines delayed access to CDI BeanManager. Starting in 5.1 the preferred means for CDI
|
||||||
|
* bootstrapping is through org.hibernate.jpa.event.spi.jpa.ExtendedBeanManager
|
||||||
|
*
|
||||||
|
* @since 5.0.8
|
||||||
|
*/
|
||||||
|
String DELAY_CDI_ACCESS = "hibernate.delay_cdi_access";
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import java.io.Serializable;
|
||||||
import org.hibernate.event.internal.DefaultDeleteEventListener;
|
import org.hibernate.event.internal.DefaultDeleteEventListener;
|
||||||
import org.hibernate.event.spi.DeleteEvent;
|
import org.hibernate.event.spi.DeleteEvent;
|
||||||
import org.hibernate.event.spi.EventSource;
|
import org.hibernate.event.spi.EventSource;
|
||||||
import org.hibernate.jpa.event.internal.jpa.CallbackRegistryConsumer;
|
import org.hibernate.jpa.event.spi.jpa.CallbackRegistryConsumer;
|
||||||
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import org.hibernate.engine.spi.EntityEntry;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.engine.spi.Status;
|
import org.hibernate.engine.spi.Status;
|
||||||
import org.hibernate.event.internal.DefaultFlushEntityEventListener;
|
import org.hibernate.event.internal.DefaultFlushEntityEventListener;
|
||||||
import org.hibernate.jpa.event.internal.jpa.CallbackRegistryConsumer;
|
import org.hibernate.jpa.event.spi.jpa.CallbackRegistryConsumer;
|
||||||
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
||||||
import org.hibernate.metadata.ClassMetadata;
|
import org.hibernate.metadata.ClassMetadata;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
|
@ -10,7 +10,7 @@ import java.io.Serializable;
|
||||||
|
|
||||||
import org.hibernate.event.internal.DefaultMergeEventListener;
|
import org.hibernate.event.internal.DefaultMergeEventListener;
|
||||||
import org.hibernate.event.spi.EventSource;
|
import org.hibernate.event.spi.EventSource;
|
||||||
import org.hibernate.jpa.event.internal.jpa.CallbackRegistryConsumer;
|
import org.hibernate.jpa.event.spi.jpa.CallbackRegistryConsumer;
|
||||||
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -15,7 +15,7 @@ import org.hibernate.engine.spi.CascadingAction;
|
||||||
import org.hibernate.engine.spi.CascadingActions;
|
import org.hibernate.engine.spi.CascadingActions;
|
||||||
import org.hibernate.event.internal.DefaultPersistEventListener;
|
import org.hibernate.event.internal.DefaultPersistEventListener;
|
||||||
import org.hibernate.event.spi.EventSource;
|
import org.hibernate.event.spi.EventSource;
|
||||||
import org.hibernate.jpa.event.internal.jpa.CallbackRegistryConsumer;
|
import org.hibernate.jpa.event.spi.jpa.CallbackRegistryConsumer;
|
||||||
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
||||||
import org.hibernate.type.CollectionType;
|
import org.hibernate.type.CollectionType;
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ package org.hibernate.jpa.event.internal.core;
|
||||||
|
|
||||||
import org.hibernate.event.spi.PostDeleteEvent;
|
import org.hibernate.event.spi.PostDeleteEvent;
|
||||||
import org.hibernate.event.spi.PostDeleteEventListener;
|
import org.hibernate.event.spi.PostDeleteEventListener;
|
||||||
import org.hibernate.jpa.event.internal.jpa.CallbackRegistryConsumer;
|
import org.hibernate.jpa.event.spi.jpa.CallbackRegistryConsumer;
|
||||||
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ package org.hibernate.jpa.event.internal.core;
|
||||||
|
|
||||||
import org.hibernate.event.spi.PostInsertEvent;
|
import org.hibernate.event.spi.PostInsertEvent;
|
||||||
import org.hibernate.event.spi.PostInsertEventListener;
|
import org.hibernate.event.spi.PostInsertEventListener;
|
||||||
import org.hibernate.jpa.event.internal.jpa.CallbackRegistryConsumer;
|
import org.hibernate.jpa.event.spi.jpa.CallbackRegistryConsumer;
|
||||||
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ package org.hibernate.jpa.event.internal.core;
|
||||||
|
|
||||||
import org.hibernate.event.spi.PostLoadEvent;
|
import org.hibernate.event.spi.PostLoadEvent;
|
||||||
import org.hibernate.event.spi.PostLoadEventListener;
|
import org.hibernate.event.spi.PostLoadEventListener;
|
||||||
import org.hibernate.jpa.event.internal.jpa.CallbackRegistryConsumer;
|
import org.hibernate.jpa.event.spi.jpa.CallbackRegistryConsumer;
|
||||||
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,7 +17,7 @@ import org.hibernate.event.spi.PostCollectionUpdateEvent;
|
||||||
import org.hibernate.event.spi.PostCollectionUpdateEventListener;
|
import org.hibernate.event.spi.PostCollectionUpdateEventListener;
|
||||||
import org.hibernate.event.spi.PostUpdateEvent;
|
import org.hibernate.event.spi.PostUpdateEvent;
|
||||||
import org.hibernate.event.spi.PostUpdateEventListener;
|
import org.hibernate.event.spi.PostUpdateEventListener;
|
||||||
import org.hibernate.jpa.event.internal.jpa.CallbackRegistryConsumer;
|
import org.hibernate.jpa.event.spi.jpa.CallbackRegistryConsumer;
|
||||||
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import java.io.Serializable;
|
||||||
|
|
||||||
import org.hibernate.event.internal.DefaultSaveEventListener;
|
import org.hibernate.event.internal.DefaultSaveEventListener;
|
||||||
import org.hibernate.event.spi.EventSource;
|
import org.hibernate.event.spi.EventSource;
|
||||||
import org.hibernate.jpa.event.internal.jpa.CallbackRegistryConsumer;
|
import org.hibernate.jpa.event.spi.jpa.CallbackRegistryConsumer;
|
||||||
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -10,7 +10,7 @@ import java.io.Serializable;
|
||||||
|
|
||||||
import org.hibernate.event.internal.DefaultSaveOrUpdateEventListener;
|
import org.hibernate.event.internal.DefaultSaveOrUpdateEventListener;
|
||||||
import org.hibernate.event.spi.EventSource;
|
import org.hibernate.event.spi.EventSource;
|
||||||
import org.hibernate.jpa.event.internal.jpa.CallbackRegistryConsumer;
|
import org.hibernate.jpa.event.spi.jpa.CallbackRegistryConsumer;
|
||||||
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.jpa.event.internal.jpa;
|
||||||
|
|
||||||
|
import org.hibernate.jpa.event.spi.jpa.Callback;
|
||||||
|
import org.hibernate.jpa.event.spi.jpa.CallbackType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public abstract class AbstractCallback implements Callback {
|
||||||
|
private final CallbackType callbackType;
|
||||||
|
|
||||||
|
public AbstractCallback(CallbackType callbackType) {
|
||||||
|
this.callbackType = callbackType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isActive() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CallbackType getCallbackType() {
|
||||||
|
return callbackType;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,76 +0,0 @@
|
||||||
/*
|
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
|
||||||
*
|
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
|
||||||
*/
|
|
||||||
package org.hibernate.jpa.event.internal.jpa;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import javax.enterprise.context.spi.CreationalContext;
|
|
||||||
import javax.enterprise.inject.spi.AnnotatedType;
|
|
||||||
import javax.enterprise.inject.spi.BeanManager;
|
|
||||||
import javax.enterprise.inject.spi.InjectionTarget;
|
|
||||||
|
|
||||||
import org.hibernate.jpa.event.spi.jpa.ListenerFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CID-based implementation of the ListenerFactory contract. Listener instances are kept in a map keyed by Class
|
|
||||||
* to achieve singleton-ness.
|
|
||||||
*
|
|
||||||
* @author Steve Ebersole
|
|
||||||
*/
|
|
||||||
public class BeanManagerListenerFactory implements ListenerFactory {
|
|
||||||
private final BeanManager beanManager;
|
|
||||||
private final Map<Class,BeanMetaData> listeners = new ConcurrentHashMap<Class, BeanMetaData>();
|
|
||||||
|
|
||||||
public static BeanManagerListenerFactory fromBeanManagerReference(Object beanManagerReference) {
|
|
||||||
return new BeanManagerListenerFactory( ( BeanManager ) beanManagerReference );
|
|
||||||
}
|
|
||||||
|
|
||||||
public BeanManagerListenerFactory(BeanManager beanManager) {
|
|
||||||
this.beanManager = beanManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T buildListener(Class<T> listenerClass) {
|
|
||||||
BeanMetaData<T> beanMetaData = listeners.get( listenerClass );
|
|
||||||
if ( beanMetaData == null ) {
|
|
||||||
beanMetaData = new BeanMetaData<T>( listenerClass );
|
|
||||||
listeners.put( listenerClass, beanMetaData );
|
|
||||||
}
|
|
||||||
return beanMetaData.instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void release() {
|
|
||||||
for ( BeanMetaData beanMetaData : listeners.values() ) {
|
|
||||||
beanMetaData.release();
|
|
||||||
}
|
|
||||||
listeners.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private class BeanMetaData<T> {
|
|
||||||
private final InjectionTarget<T> injectionTarget;
|
|
||||||
private final CreationalContext<T> creationalContext;
|
|
||||||
private final T instance;
|
|
||||||
|
|
||||||
private BeanMetaData(Class<T> listenerClass) {
|
|
||||||
AnnotatedType<T> 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -25,33 +25,36 @@ import org.hibernate.annotations.common.reflection.ReflectionManager;
|
||||||
import org.hibernate.annotations.common.reflection.XClass;
|
import org.hibernate.annotations.common.reflection.XClass;
|
||||||
import org.hibernate.annotations.common.reflection.XMethod;
|
import org.hibernate.annotations.common.reflection.XMethod;
|
||||||
import org.hibernate.jpa.event.spi.jpa.Callback;
|
import org.hibernate.jpa.event.spi.jpa.Callback;
|
||||||
|
import org.hibernate.jpa.event.spi.jpa.CallbackType;
|
||||||
|
import org.hibernate.jpa.event.spi.jpa.CallbackBuilder;
|
||||||
import org.hibernate.jpa.event.spi.jpa.ListenerFactory;
|
import org.hibernate.jpa.event.spi.jpa.ListenerFactory;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:kabir.khan@jboss.org">Kabir Khan</a>
|
* EntityCallbackBuilder implementation using HCANN ReflectionManager. "legacy" in that
|
||||||
|
* we want to move to Jandex instead.
|
||||||
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class LegacyCallbackProcessor implements CallbackProcessor {
|
public class CallbackBuilderLegacyImpl implements CallbackBuilder {
|
||||||
private static final Logger log = Logger.getLogger( LegacyCallbackProcessor.class );
|
private static final Logger log = Logger.getLogger( CallbackBuilderLegacyImpl.class );
|
||||||
|
|
||||||
private final ListenerFactory jpaListenerFactory;
|
private final ListenerFactory jpaListenerFactory;
|
||||||
private final ReflectionManager reflectionManager;
|
private final ReflectionManager reflectionManager;
|
||||||
|
|
||||||
public LegacyCallbackProcessor(ListenerFactory jpaListenerFactory, ReflectionManager reflectionManager) {
|
public CallbackBuilderLegacyImpl(ListenerFactory jpaListenerFactory, ReflectionManager reflectionManager) {
|
||||||
this.jpaListenerFactory = jpaListenerFactory;
|
this.jpaListenerFactory = jpaListenerFactory;
|
||||||
this.reflectionManager = reflectionManager;
|
this.reflectionManager = reflectionManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void processCallbacksForEntity(Object entityObject, CallbackRegistryImpl callbackRegistry) {
|
public void buildCallbacksForEntity(String entityClassName, CallbackRegistrar callbackRegistrar) {
|
||||||
final String entityClassName = (String) entityObject;
|
|
||||||
try {
|
try {
|
||||||
final XClass entityXClass = reflectionManager.classForName( entityClassName );
|
final XClass entityXClass = reflectionManager.classForName( entityClassName );
|
||||||
final Class entityClass = reflectionManager.toClass( entityXClass );
|
final Class entityClass = reflectionManager.toClass( entityXClass );
|
||||||
for ( Class annotationClass : CALLBACK_ANNOTATION_CLASSES ) {
|
for ( CallbackType callbackType : CallbackType.values() ) {
|
||||||
if ( callbackRegistry.hasRegisteredCallbacks( entityClass, annotationClass ) ) {
|
if ( callbackRegistrar.hasRegisteredCallbacks( entityClass, callbackType ) ) {
|
||||||
// this most likely means we have a class mapped multiple times using the hbm.xml
|
// this most likely means we have a class mapped multiple times using the hbm.xml
|
||||||
// "entity name" feature
|
// "entity name" feature
|
||||||
log.debugf(
|
log.debugf(
|
||||||
|
@ -59,12 +62,12 @@ public class LegacyCallbackProcessor implements CallbackProcessor {
|
||||||
"assuming this means the class was mapped twice " +
|
"assuming this means the class was mapped twice " +
|
||||||
"(using hbm.xml entity-name support) - skipping subsequent registrations",
|
"(using hbm.xml entity-name support) - skipping subsequent registrations",
|
||||||
entityClassName,
|
entityClassName,
|
||||||
annotationClass.getSimpleName()
|
callbackType.getCallbackAnnotation().getSimpleName()
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
final Callback[] callbacks = resolveCallbacks( entityXClass, annotationClass, reflectionManager );
|
final Callback[] callbacks = resolveCallbacks( entityXClass, callbackType, reflectionManager );
|
||||||
callbackRegistry.addEntityCallbacks( entityClass, annotationClass, callbacks );
|
callbackRegistrar.registerCallbacks( entityClass, callbacks );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (ClassLoadingException e) {
|
catch (ClassLoadingException e) {
|
||||||
|
@ -72,7 +75,12 @@ public class LegacyCallbackProcessor implements CallbackProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Callback[] resolveCallbacks(XClass beanClass, Class annotation, ReflectionManager reflectionManager) {
|
@Override
|
||||||
|
public void release() {
|
||||||
|
// nothign to do
|
||||||
|
}
|
||||||
|
|
||||||
|
public Callback[] resolveCallbacks(XClass beanClass, CallbackType callbackType, ReflectionManager reflectionManager) {
|
||||||
List<Callback> callbacks = new ArrayList<Callback>();
|
List<Callback> callbacks = new ArrayList<Callback>();
|
||||||
List<String> callbacksMethodNames = new ArrayList<String>(); //used to track overridden methods
|
List<String> callbacksMethodNames = new ArrayList<String>(); //used to track overridden methods
|
||||||
List<Class> orderedListeners = new ArrayList<Class>();
|
List<Class> orderedListeners = new ArrayList<Class>();
|
||||||
|
@ -83,26 +91,26 @@ public class LegacyCallbackProcessor implements CallbackProcessor {
|
||||||
Callback callback = null;
|
Callback callback = null;
|
||||||
List<XMethod> methods = currentClazz.getDeclaredMethods();
|
List<XMethod> methods = currentClazz.getDeclaredMethods();
|
||||||
for ( final XMethod xMethod : methods ) {
|
for ( final XMethod xMethod : methods ) {
|
||||||
if ( xMethod.isAnnotationPresent( annotation ) ) {
|
if ( xMethod.isAnnotationPresent( callbackType.getCallbackAnnotation() ) ) {
|
||||||
Method method = reflectionManager.toMethod( xMethod );
|
Method method = reflectionManager.toMethod( xMethod );
|
||||||
final String methodName = method.getName();
|
final String methodName = method.getName();
|
||||||
if ( !callbacksMethodNames.contains( methodName ) ) {
|
if ( !callbacksMethodNames.contains( methodName ) ) {
|
||||||
//overridden method, remove the superclass overridden method
|
//overridden method, remove the superclass overridden method
|
||||||
if ( callback == null ) {
|
if ( callback == null ) {
|
||||||
callback = new EntityCallback( method );
|
callback = new EntityCallback( method, callbackType );
|
||||||
Class returnType = method.getReturnType();
|
Class returnType = method.getReturnType();
|
||||||
Class[] args = method.getParameterTypes();
|
Class[] args = method.getParameterTypes();
|
||||||
if ( returnType != Void.TYPE || args.length != 0 ) {
|
if ( returnType != Void.TYPE || args.length != 0 ) {
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
"Callback methods annotated on the bean class must return void and take no arguments: " + annotation
|
"Callback methods annotated on the bean class must return void and take no arguments: "
|
||||||
.getName() + " - " + xMethod
|
+ callbackType.getCallbackAnnotation().getName() + " - " + xMethod
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
method.setAccessible( true );
|
method.setAccessible( true );
|
||||||
log.debugf(
|
log.debugf(
|
||||||
"Adding %s as %s callback for entity %s",
|
"Adding %s as %s callback for entity %s",
|
||||||
methodName,
|
methodName,
|
||||||
annotation.getSimpleName(),
|
callbackType.getCallbackAnnotation().getSimpleName(),
|
||||||
beanClass.getName()
|
beanClass.getName()
|
||||||
);
|
);
|
||||||
callbacks.add( 0, callback ); //superclass first
|
callbacks.add( 0, callback ); //superclass first
|
||||||
|
@ -111,7 +119,7 @@ public class LegacyCallbackProcessor implements CallbackProcessor {
|
||||||
else {
|
else {
|
||||||
throw new PersistenceException(
|
throw new PersistenceException(
|
||||||
"You can only annotate one callback method with "
|
"You can only annotate one callback method with "
|
||||||
+ annotation.getName() + " in bean class: " + beanClass.getName()
|
+ callbackType.getCallbackAnnotation().getName() + " in bean class: " + beanClass.getName()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,20 +160,24 @@ public class LegacyCallbackProcessor implements CallbackProcessor {
|
||||||
callbacksMethodNames = new ArrayList<String>();
|
callbacksMethodNames = new ArrayList<String>();
|
||||||
List<XMethod> methods = xListener.getDeclaredMethods();
|
List<XMethod> methods = xListener.getDeclaredMethods();
|
||||||
for ( final XMethod xMethod : methods ) {
|
for ( final XMethod xMethod : methods ) {
|
||||||
if ( xMethod.isAnnotationPresent( annotation ) ) {
|
if ( xMethod.isAnnotationPresent( callbackType.getCallbackAnnotation() ) ) {
|
||||||
final Method method = reflectionManager.toMethod( xMethod );
|
final Method method = reflectionManager.toMethod( xMethod );
|
||||||
final String methodName = method.getName();
|
final String methodName = method.getName();
|
||||||
if ( !callbacksMethodNames.contains( methodName ) ) {
|
if ( !callbacksMethodNames.contains( methodName ) ) {
|
||||||
//overridden method, remove the superclass overridden method
|
//overridden method, remove the superclass overridden method
|
||||||
if ( callback == null ) {
|
if ( callback == null ) {
|
||||||
callback = new ListenerCallback( jpaListenerFactory.buildListener( listener ), method );
|
callback = new ListenerCallback(
|
||||||
|
jpaListenerFactory.buildListener( listener ),
|
||||||
|
method,
|
||||||
|
callbackType
|
||||||
|
);
|
||||||
|
|
||||||
Class returnType = method.getReturnType();
|
Class returnType = method.getReturnType();
|
||||||
Class[] args = method.getParameterTypes();
|
Class[] args = method.getParameterTypes();
|
||||||
if ( returnType != Void.TYPE || args.length != 1 ) {
|
if ( returnType != Void.TYPE || args.length != 1 ) {
|
||||||
throw new PersistenceException(
|
throw new PersistenceException(
|
||||||
"Callback methods annotated in a listener bean class must return void and take one argument: " + annotation
|
"Callback methods annotated in a listener bean class must return void and take one argument: "
|
||||||
.getName() + " - " + method
|
+ callbackType.getCallbackAnnotation().getName() + " - " + method
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if ( !method.isAccessible() ) {
|
if ( !method.isAccessible() ) {
|
||||||
|
@ -174,7 +186,7 @@ public class LegacyCallbackProcessor implements CallbackProcessor {
|
||||||
log.debugf(
|
log.debugf(
|
||||||
"Adding %s as %s callback for entity %s",
|
"Adding %s as %s callback for entity %s",
|
||||||
methodName,
|
methodName,
|
||||||
annotation.getSimpleName(),
|
callbackType.getCallbackAnnotation().getSimpleName(),
|
||||||
beanClass.getName()
|
beanClass.getName()
|
||||||
);
|
);
|
||||||
callbacks.add( 0, callback ); // listeners first
|
callbacks.add( 0, callback ); // listeners first
|
||||||
|
@ -182,8 +194,9 @@ public class LegacyCallbackProcessor implements CallbackProcessor {
|
||||||
else {
|
else {
|
||||||
throw new PersistenceException(
|
throw new PersistenceException(
|
||||||
"You can only annotate one callback method with "
|
"You can only annotate one callback method with "
|
||||||
+ annotation.getName() + " in bean class: " + beanClass.getName() + " and callback listener: "
|
+ callbackType.getCallbackAnnotation().getName()
|
||||||
+ listener.getName()
|
+ " in bean class: " + beanClass.getName()
|
||||||
|
+ " and callback listener: " + listener.getName()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,9 +245,4 @@ public class LegacyCallbackProcessor implements CallbackProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void release() {
|
|
||||||
// nothing to do here
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,41 +0,0 @@
|
||||||
/*
|
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
|
||||||
*
|
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
|
||||||
*/
|
|
||||||
package org.hibernate.jpa.event.internal.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, CallbackRegistryImpl registry);
|
|
||||||
|
|
||||||
public void release();
|
|
||||||
}
|
|
|
@ -8,16 +8,11 @@ package org.hibernate.jpa.event.internal.jpa;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import javax.persistence.PersistenceException;
|
import javax.persistence.PersistenceException;
|
||||||
import javax.persistence.PostLoad;
|
|
||||||
import javax.persistence.PostPersist;
|
|
||||||
import javax.persistence.PostRemove;
|
|
||||||
import javax.persistence.PostUpdate;
|
|
||||||
import javax.persistence.PrePersist;
|
|
||||||
import javax.persistence.PreRemove;
|
|
||||||
import javax.persistence.PreUpdate;
|
|
||||||
|
|
||||||
import org.hibernate.jpa.event.spi.jpa.Callback;
|
import org.hibernate.jpa.event.spi.jpa.Callback;
|
||||||
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
||||||
|
import org.hibernate.jpa.event.spi.jpa.CallbackType;
|
||||||
|
import org.hibernate.jpa.event.spi.jpa.CallbackBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keep track of all lifecycle callbacks and listeners for a given persistence unit
|
* Keep track of all lifecycle callbacks and listeners for a given persistence unit
|
||||||
|
@ -26,7 +21,7 @@ import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({"unchecked", "serial"})
|
@SuppressWarnings({"unchecked", "serial"})
|
||||||
public class CallbackRegistryImpl implements CallbackRegistry {
|
public class CallbackRegistryImpl implements CallbackRegistry, CallbackBuilder.CallbackRegistrar {
|
||||||
private HashMap<Class, Callback[]> preCreates = new HashMap<Class, Callback[]>();
|
private HashMap<Class, Callback[]> preCreates = new HashMap<Class, Callback[]>();
|
||||||
private HashMap<Class, Callback[]> postCreates = new HashMap<Class, Callback[]>();
|
private HashMap<Class, Callback[]> postCreates = new HashMap<Class, Callback[]>();
|
||||||
private HashMap<Class, Callback[]> preRemoves = new HashMap<Class, Callback[]>();
|
private HashMap<Class, Callback[]> preRemoves = new HashMap<Class, Callback[]>();
|
||||||
|
@ -36,13 +31,27 @@ public class CallbackRegistryImpl implements CallbackRegistry {
|
||||||
private HashMap<Class, Callback[]> postLoads = new HashMap<Class, Callback[]>();
|
private HashMap<Class, Callback[]> postLoads = new HashMap<Class, Callback[]>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void preCreate(Object bean) {
|
public boolean hasRegisteredCallbacks(Class entityClass, CallbackType callbackType) {
|
||||||
callback( preCreates.get( bean.getClass() ), bean );
|
final HashMap<Class, Callback[]> map = determineAppropriateCallbackMap( callbackType );
|
||||||
|
return notEmpty( map.get( entityClass ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasPostCreateCallbacks(Class entityClass) {
|
public void registerCallbacks(Class entityClass, Callback[] callbacks) {
|
||||||
return notEmpty( preCreates.get( entityClass ) );
|
if ( callbacks == null || callbacks.length == 0 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final HashMap<Class, Callback[]> map = determineAppropriateCallbackMap( callbacks[0].getCallbackType() );
|
||||||
|
if ( map.containsKey( entityClass ) ) {
|
||||||
|
throw new PersistenceException( "Error build callback listeners; entity [" + entityClass.getName() + " was already processed" );
|
||||||
|
}
|
||||||
|
map.put( entityClass, callbacks );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preCreate(Object bean) {
|
||||||
|
callback( preCreates.get( bean.getClass() ), bean );
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean notEmpty(Callback[] callbacks) {
|
private boolean notEmpty(Callback[] callbacks) {
|
||||||
|
@ -59,11 +68,6 @@ public class CallbackRegistryImpl implements CallbackRegistry {
|
||||||
return callback( preUpdates.get( bean.getClass() ), bean );
|
return callback( preUpdates.get( bean.getClass() ), bean );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasPostUpdateCallbacks(Class entityClass) {
|
|
||||||
return notEmpty( postUpdates.get( entityClass ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void postUpdate(Object bean) {
|
public void postUpdate(Object bean) {
|
||||||
callback( postUpdates.get( bean.getClass() ), bean );
|
callback( postUpdates.get( bean.getClass() ), bean );
|
||||||
|
@ -74,11 +78,6 @@ public class CallbackRegistryImpl implements CallbackRegistry {
|
||||||
callback( preRemoves.get( bean.getClass() ), bean );
|
callback( preRemoves.get( bean.getClass() ), bean );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasPostRemoveCallbacks(Class entityClass) {
|
|
||||||
return notEmpty( postRemoves.get( entityClass ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void postRemove(Object bean) {
|
public void postRemove(Object bean) {
|
||||||
callback( postRemoves.get( bean.getClass() ), bean );
|
callback( postRemoves.get( bean.getClass() ), bean );
|
||||||
|
@ -101,56 +100,36 @@ public class CallbackRegistryImpl implements CallbackRegistry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private HashMap<Class, Callback[]> determineAppropriateCallbackMap(CallbackType callbackType) {
|
||||||
public boolean hasRegisteredCallbacks(Class entityClass, Class annotationClass) {
|
if ( callbackType == CallbackType.PRE_PERSIST ) {
|
||||||
final HashMap<Class, Callback[]> map = determineAppropriateCallbackMap( annotationClass );
|
|
||||||
return map != null && map.containsKey( entityClass );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Great care should be taken calling this. Not a fan of it being public, but that is needed because of
|
|
||||||
* @param entityClass
|
|
||||||
* @param annotationClass
|
|
||||||
* @param callbacks
|
|
||||||
*/
|
|
||||||
public void addEntityCallbacks(Class entityClass, Class annotationClass, Callback[] callbacks) {
|
|
||||||
final HashMap<Class, Callback[]> map = determineAppropriateCallbackMap( annotationClass );
|
|
||||||
if ( map.containsKey( entityClass ) ) {
|
|
||||||
throw new PersistenceException( "Error build callback listeners; entity [" + entityClass.getName() + " was already processed" );
|
|
||||||
}
|
|
||||||
map.put( entityClass, callbacks );
|
|
||||||
}
|
|
||||||
|
|
||||||
private HashMap<Class, Callback[]> determineAppropriateCallbackMap(Class annotationClass) {
|
|
||||||
if ( PrePersist.class.equals( annotationClass ) ) {
|
|
||||||
return preCreates;
|
return preCreates;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( PostPersist.class.equals( annotationClass ) ) {
|
if ( callbackType == CallbackType.POST_PERSIST ) {
|
||||||
return postCreates;
|
return postCreates;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( PreRemove.class.equals( annotationClass ) ) {
|
if ( callbackType == CallbackType.PRE_REMOVE ) {
|
||||||
return preRemoves;
|
return preRemoves;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( PostRemove.class.equals( annotationClass ) ) {
|
if ( callbackType == CallbackType.POST_REMOVE ) {
|
||||||
return postRemoves;
|
return postRemoves;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( PreUpdate.class.equals( annotationClass ) ) {
|
if ( callbackType == CallbackType.PRE_UPDATE ) {
|
||||||
return preUpdates;
|
return preUpdates;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( PostUpdate.class.equals( annotationClass ) ) {
|
if ( callbackType == CallbackType.POST_UPDATE ) {
|
||||||
return postUpdates;
|
return postUpdates;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( PostLoad.class.equals( annotationClass ) ) {
|
if ( callbackType == CallbackType.POST_LOAD ) {
|
||||||
return postLoads;
|
return postLoads;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new PersistenceException( "Unrecognized JPA callback annotation [" + annotationClass.getName() + "]" );
|
throw new PersistenceException( "Unrecognized JPA callback type [" + callbackType + "]" );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void release() {
|
public void release() {
|
||||||
|
@ -165,4 +144,54 @@ public class CallbackRegistryImpl implements CallbackRegistry {
|
||||||
|
|
||||||
postLoads.clear();
|
postLoads.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// deprecations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPostCreateCallbacks(Class entityClass) {
|
||||||
|
return notEmpty( preCreates.get( entityClass ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPostUpdateCallbacks(Class entityClass) {
|
||||||
|
return notEmpty( postUpdates.get( entityClass ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPostRemoveCallbacks(Class entityClass) {
|
||||||
|
return notEmpty( postRemoves.get( entityClass ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasRegisteredCallbacks(Class entityClass, Class annotationClass) {
|
||||||
|
final HashMap<Class, Callback[]> map = determineAppropriateCallbackMap( toCallbackType( annotationClass ) );
|
||||||
|
return map != null && map.containsKey( entityClass );
|
||||||
|
}
|
||||||
|
|
||||||
|
private CallbackType toCallbackType(Class annotationClass) {
|
||||||
|
if ( annotationClass == CallbackType.POST_LOAD.getCallbackAnnotation() ) {
|
||||||
|
return CallbackType.POST_LOAD;
|
||||||
|
}
|
||||||
|
else if ( annotationClass == CallbackType.PRE_PERSIST.getCallbackAnnotation() ) {
|
||||||
|
return CallbackType.PRE_PERSIST;
|
||||||
|
}
|
||||||
|
else if ( annotationClass == CallbackType.POST_PERSIST.getCallbackAnnotation() ) {
|
||||||
|
return CallbackType.POST_PERSIST;
|
||||||
|
}
|
||||||
|
else if ( annotationClass == CallbackType.PRE_UPDATE.getCallbackAnnotation() ) {
|
||||||
|
return CallbackType.PRE_UPDATE;
|
||||||
|
}
|
||||||
|
else if ( annotationClass == CallbackType.POST_UPDATE.getCallbackAnnotation() ) {
|
||||||
|
return CallbackType.POST_UPDATE;
|
||||||
|
}
|
||||||
|
else if ( annotationClass == CallbackType.PRE_REMOVE.getCallbackAnnotation() ) {
|
||||||
|
return CallbackType.PRE_REMOVE;
|
||||||
|
}
|
||||||
|
else if ( annotationClass == CallbackType.POST_REMOVE.getCallbackAnnotation() ) {
|
||||||
|
return CallbackType.POST_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new PersistenceException( "Unrecognized JPA callback annotation [" + annotationClass + "]" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
import org.hibernate.jpa.event.spi.jpa.Callback;
|
import org.hibernate.jpa.event.spi.jpa.Callback;
|
||||||
|
import org.hibernate.jpa.event.spi.jpa.CallbackType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a JPA callback on the entity itself
|
* Represents a JPA callback on the entity itself
|
||||||
|
@ -17,10 +18,11 @@ import org.hibernate.jpa.event.spi.jpa.Callback;
|
||||||
* @author <a href="mailto:kabir.khan@jboss.org">Kabir Khan</a>
|
* @author <a href="mailto:kabir.khan@jboss.org">Kabir Khan</a>
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class EntityCallback implements Callback {
|
public class EntityCallback extends AbstractCallback implements Callback {
|
||||||
private Method callbackMethod;
|
private final Method callbackMethod;
|
||||||
|
|
||||||
public EntityCallback(Method callbackMethod) {
|
public EntityCallback(Method callbackMethod, CallbackType callbackType) {
|
||||||
|
super( callbackType );
|
||||||
this.callbackMethod = callbackMethod;
|
this.callbackMethod = callbackMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,9 +45,4 @@ public class EntityCallback implements Callback {
|
||||||
throw new RuntimeException( e );
|
throw new RuntimeException( e );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isActive() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@ import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
import org.hibernate.jpa.event.spi.jpa.Callback;
|
import org.hibernate.jpa.event.spi.jpa.Callback;
|
||||||
|
import org.hibernate.jpa.event.spi.jpa.CallbackType;
|
||||||
|
import org.hibernate.jpa.event.spi.jpa.Listener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a JPA callback using a dedicated listener
|
* Represents a JPA callback using a dedicated listener
|
||||||
|
@ -17,11 +19,12 @@ import org.hibernate.jpa.event.spi.jpa.Callback;
|
||||||
* @author <a href="mailto:kabir.khan@jboss.org">Kabir Khan</a>
|
* @author <a href="mailto:kabir.khan@jboss.org">Kabir Khan</a>
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class ListenerCallback implements Callback {
|
public class ListenerCallback extends AbstractCallback implements Callback {
|
||||||
private final Method callbackMethod;
|
private final Method callbackMethod;
|
||||||
private final Object listenerInstance;
|
private final Listener listenerInstance;
|
||||||
|
|
||||||
public ListenerCallback(Object listenerInstance, Method callbackMethod) {
|
public ListenerCallback(Listener listenerInstance, Method callbackMethod, CallbackType callbackType) {
|
||||||
|
super( callbackType );
|
||||||
this.listenerInstance = listenerInstance;
|
this.listenerInstance = listenerInstance;
|
||||||
this.callbackMethod = callbackMethod;
|
this.callbackMethod = callbackMethod;
|
||||||
}
|
}
|
||||||
|
@ -29,7 +32,7 @@ public class ListenerCallback implements Callback {
|
||||||
@Override
|
@Override
|
||||||
public boolean performCallback(Object entity) {
|
public boolean performCallback(Object entity) {
|
||||||
try {
|
try {
|
||||||
callbackMethod.invoke( listenerInstance, entity );
|
callbackMethod.invoke( listenerInstance.getListener(), entity );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (InvocationTargetException e) {
|
catch (InvocationTargetException e) {
|
||||||
|
@ -45,9 +48,4 @@ public class ListenerCallback implements Callback {
|
||||||
throw new RuntimeException( e );
|
throw new RuntimeException( e );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isActive() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.jpa.event.internal.jpa;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import javax.enterprise.context.spi.CreationalContext;
|
||||||
|
import javax.enterprise.inject.spi.AnnotatedType;
|
||||||
|
import javax.enterprise.inject.spi.BeanManager;
|
||||||
|
import javax.enterprise.inject.spi.InjectionTarget;
|
||||||
|
|
||||||
|
import org.hibernate.jpa.event.spi.jpa.Listener;
|
||||||
|
import org.hibernate.jpa.event.spi.jpa.ListenerFactory;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CDI-based implementation of the ListenerFactory contract. This implementation
|
||||||
|
* delayes access to the CDI BeanManager until first need.
|
||||||
|
* <p/>
|
||||||
|
* This class appears unused, but that is because it is only referenced via reflection from
|
||||||
|
* {@link org.hibernate.jpa.event.spi.jpa.ListenerFactoryBuilder}.
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class ListenerFactoryBeanManagerDelayedImpl implements ListenerFactory {
|
||||||
|
private static final Logger log = Logger.getLogger( ListenerFactoryBeanManagerDelayedImpl.class );
|
||||||
|
|
||||||
|
private final BeanManager beanManager;
|
||||||
|
private final Map<Class,ListenerImpl> listenerMap = new ConcurrentHashMap<Class, ListenerImpl>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used via reflection from ListenerFactoryBuilder, the intent being to isolate CDI dependency
|
||||||
|
* to just this class and its delegates in the case that a BeanManager is passed.
|
||||||
|
*
|
||||||
|
* @param reference The BeanManager reference
|
||||||
|
*
|
||||||
|
* @return A instantiated ListenerFactoryBeanManagerImpl
|
||||||
|
*/
|
||||||
|
public static ListenerFactoryBeanManagerDelayedImpl fromBeanManagerReference(Object reference) {
|
||||||
|
return new ListenerFactoryBeanManagerDelayedImpl( (BeanManager) reference );
|
||||||
|
}
|
||||||
|
|
||||||
|
public ListenerFactoryBeanManagerDelayedImpl(BeanManager beanManager) {
|
||||||
|
this.beanManager = beanManager;
|
||||||
|
log.debugf( "Delayed access requested to CDI BeanManager : " + beanManager );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> Listener<T> buildListener(Class<T> listenerClass) {
|
||||||
|
ListenerImpl listenerImpl = listenerMap.get( listenerClass );
|
||||||
|
if ( listenerImpl == null ) {
|
||||||
|
listenerImpl = new ListenerImpl( listenerClass );
|
||||||
|
listenerMap.put( listenerClass, listenerImpl );
|
||||||
|
}
|
||||||
|
return (Listener<T>) listenerImpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void release() {
|
||||||
|
for ( ListenerImpl listenerImpl : listenerMap.values() ) {
|
||||||
|
listenerImpl.release();
|
||||||
|
}
|
||||||
|
listenerMap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ListenerImpl<T> implements Listener<T> {
|
||||||
|
private final Class<T> listenerClass;
|
||||||
|
|
||||||
|
private boolean initialized = false;
|
||||||
|
|
||||||
|
private InjectionTarget<T> injectionTarget;
|
||||||
|
private CreationalContext<T> creationalContext;
|
||||||
|
private T listenerInstance;
|
||||||
|
|
||||||
|
private ListenerImpl(Class<T> listenerClass) {
|
||||||
|
this.listenerClass = listenerClass;
|
||||||
|
log.debugf( "Delayed CDI listener built : " + listenerClass );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initialize() {
|
||||||
|
log.debug( "Initializing delayed CDI listener on first use : " + listenerClass );
|
||||||
|
AnnotatedType<T> annotatedType = beanManager.createAnnotatedType( listenerClass );
|
||||||
|
this.injectionTarget = beanManager.createInjectionTarget( annotatedType );
|
||||||
|
this.creationalContext = beanManager.createCreationalContext( null );
|
||||||
|
|
||||||
|
this.listenerInstance = injectionTarget.produce( creationalContext );
|
||||||
|
injectionTarget.inject( this.listenerInstance, creationalContext );
|
||||||
|
|
||||||
|
injectionTarget.postConstruct( this.listenerInstance );
|
||||||
|
|
||||||
|
this.initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T getListener() {
|
||||||
|
if ( !initialized ) {
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
return listenerInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void release() {
|
||||||
|
if ( !initialized ) {
|
||||||
|
log.debug( "Skipping release for CDI listener [" + listenerClass + "] as it was not initialized" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug( "Releasing CDI listener : " + listenerClass );
|
||||||
|
|
||||||
|
injectionTarget.preDestroy( listenerInstance );
|
||||||
|
injectionTarget.dispose( listenerInstance );
|
||||||
|
creationalContext.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.jpa.event.internal.jpa;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import javax.enterprise.context.spi.CreationalContext;
|
||||||
|
import javax.enterprise.inject.spi.AnnotatedType;
|
||||||
|
import javax.enterprise.inject.spi.BeanManager;
|
||||||
|
import javax.enterprise.inject.spi.InjectionTarget;
|
||||||
|
|
||||||
|
import org.hibernate.jpa.event.spi.jpa.Listener;
|
||||||
|
import org.hibernate.jpa.event.spi.jpa.ListenerFactory;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CDI-based implementation of the ListenerFactory contract. This implementation works in
|
||||||
|
* the JPA standard prescribed manner.
|
||||||
|
* <p/>
|
||||||
|
* This class appears unused, but that is because it is only referenced via reflection from
|
||||||
|
* {@link org.hibernate.jpa.event.spi.jpa.ListenerFactoryBuilder}.
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class ListenerFactoryBeanManagerStandardImpl implements ListenerFactory {
|
||||||
|
private static final Logger log = Logger.getLogger( ListenerFactoryBeanManagerStandardImpl.class );
|
||||||
|
|
||||||
|
private final BeanManager beanManager;
|
||||||
|
private final Map<Class,ListenerImpl> listenerMap = new ConcurrentHashMap<Class, ListenerImpl>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used via reflection from ListenerFactoryBuilder, the intent being to isolate CDI dependency
|
||||||
|
* to just this class and its delegates in the case that a BeanManager is passed.
|
||||||
|
*
|
||||||
|
* @param reference The BeanManager reference
|
||||||
|
*
|
||||||
|
* @return A instantiated ListenerFactoryBeanManagerImpl
|
||||||
|
*/
|
||||||
|
public static ListenerFactoryBeanManagerStandardImpl fromBeanManagerReference(Object reference) {
|
||||||
|
return new ListenerFactoryBeanManagerStandardImpl( (BeanManager) reference );
|
||||||
|
}
|
||||||
|
|
||||||
|
public ListenerFactoryBeanManagerStandardImpl(BeanManager beanManager) {
|
||||||
|
this.beanManager = beanManager;
|
||||||
|
log.debugf( "Standard access requested to CDI BeanManager : " + beanManager );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> Listener<T> buildListener(Class<T> listenerClass) {
|
||||||
|
ListenerImpl listenerImpl = listenerMap.get( listenerClass );
|
||||||
|
if ( listenerImpl == null ) {
|
||||||
|
listenerImpl = new ListenerImpl( listenerClass );
|
||||||
|
listenerMap.put( listenerClass, listenerImpl );
|
||||||
|
}
|
||||||
|
return (Listener<T>) listenerImpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void release() {
|
||||||
|
for ( ListenerImpl listenerImpl : listenerMap.values() ) {
|
||||||
|
listenerImpl.release();
|
||||||
|
}
|
||||||
|
listenerMap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ListenerImpl<T> implements Listener<T> {
|
||||||
|
private final InjectionTarget<T> injectionTarget;
|
||||||
|
private final CreationalContext<T> creationalContext;
|
||||||
|
private final T listenerInstance;
|
||||||
|
|
||||||
|
private ListenerImpl(Class<T> listenerClass) {
|
||||||
|
AnnotatedType<T> annotatedType = beanManager.createAnnotatedType( listenerClass );
|
||||||
|
this.injectionTarget = beanManager.createInjectionTarget( annotatedType );
|
||||||
|
this.creationalContext = beanManager.createCreationalContext( null );
|
||||||
|
|
||||||
|
this.listenerInstance = injectionTarget.produce( creationalContext );
|
||||||
|
injectionTarget.inject( this.listenerInstance, creationalContext );
|
||||||
|
|
||||||
|
injectionTarget.postConstruct( this.listenerInstance );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T getListener() {
|
||||||
|
return listenerInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void release() {
|
||||||
|
injectionTarget.preDestroy( listenerInstance );
|
||||||
|
injectionTarget.dispose( listenerInstance );
|
||||||
|
creationalContext.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.jpa.event.internal.jpa;
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import javax.persistence.PersistenceException;
|
||||||
|
|
||||||
|
import org.hibernate.jpa.event.spi.jpa.Listener;
|
||||||
|
import org.hibernate.jpa.event.spi.jpa.ListenerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard implementation of the ListenerFactory contract using simple instantiation.
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class ListenerFactoryStandardImpl implements ListenerFactory {
|
||||||
|
private final ConcurrentHashMap<Class, ListenerImpl> listenerInstances = new ConcurrentHashMap<Class, ListenerImpl>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> Listener<T> buildListener(Class<T> listenerClass) {
|
||||||
|
ListenerImpl listenerImpl = listenerInstances.get( listenerClass );
|
||||||
|
if ( listenerImpl == null ) {
|
||||||
|
try {
|
||||||
|
T listenerInstance = listenerClass.newInstance();
|
||||||
|
listenerImpl = new ListenerImpl( listenerInstance );
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
throw new PersistenceException(
|
||||||
|
"Unable to create instance of " + listenerClass.getName() + " as a JPA callback listener",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ListenerImpl existing = listenerInstances.putIfAbsent(
|
||||||
|
listenerClass,
|
||||||
|
listenerImpl
|
||||||
|
);
|
||||||
|
if ( existing != null ) {
|
||||||
|
listenerImpl = existing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (Listener<T>) listenerImpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void release() {
|
||||||
|
listenerInstances.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ListenerImpl<T> implements Listener<T> {
|
||||||
|
private final T listenerInstance;
|
||||||
|
|
||||||
|
public ListenerImpl(T listenerInstance) {
|
||||||
|
this.listenerInstance = listenerInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T getListener() {
|
||||||
|
return listenerInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
|
||||||
*
|
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
|
||||||
*/
|
|
||||||
package org.hibernate.jpa.event.internal.jpa;
|
|
||||||
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import javax.persistence.PersistenceException;
|
|
||||||
|
|
||||||
import org.hibernate.jpa.event.spi.jpa.ListenerFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 final ConcurrentHashMap listenerInstances = new ConcurrentHashMap();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <T> T buildListener(Class<T> 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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Object existing = listenerInstances.putIfAbsent( listenerClass, listenerInstance );
|
|
||||||
if ( existing != null ) {
|
|
||||||
listenerInstance = existing;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (T) listenerInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void release() {
|
|
||||||
listenerInstances.clear();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -40,12 +40,12 @@ import org.hibernate.jpa.event.internal.core.JpaPostLoadEventListener;
|
||||||
import org.hibernate.jpa.event.internal.core.JpaPostUpdateEventListener;
|
import org.hibernate.jpa.event.internal.core.JpaPostUpdateEventListener;
|
||||||
import org.hibernate.jpa.event.internal.core.JpaSaveEventListener;
|
import org.hibernate.jpa.event.internal.core.JpaSaveEventListener;
|
||||||
import org.hibernate.jpa.event.internal.core.JpaSaveOrUpdateEventListener;
|
import org.hibernate.jpa.event.internal.core.JpaSaveOrUpdateEventListener;
|
||||||
import org.hibernate.jpa.event.internal.jpa.CallbackProcessor;
|
|
||||||
import org.hibernate.jpa.event.internal.jpa.CallbackRegistryConsumer;
|
|
||||||
import org.hibernate.jpa.event.internal.jpa.CallbackRegistryImpl;
|
import org.hibernate.jpa.event.internal.jpa.CallbackRegistryImpl;
|
||||||
import org.hibernate.jpa.event.internal.jpa.LegacyCallbackProcessor;
|
import org.hibernate.jpa.event.internal.jpa.CallbackBuilderLegacyImpl;
|
||||||
import org.hibernate.jpa.event.internal.jpa.StandardListenerFactory;
|
import org.hibernate.jpa.event.spi.jpa.CallbackRegistryConsumer;
|
||||||
|
import org.hibernate.jpa.event.spi.jpa.CallbackBuilder;
|
||||||
import org.hibernate.jpa.event.spi.jpa.ListenerFactory;
|
import org.hibernate.jpa.event.spi.jpa.ListenerFactory;
|
||||||
|
import org.hibernate.jpa.event.spi.jpa.ListenerFactoryBuilder;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||||
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
|
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
|
||||||
|
@ -57,7 +57,7 @@ import org.hibernate.service.spi.SessionFactoryServiceRegistry;
|
||||||
*/
|
*/
|
||||||
public class JpaIntegrator implements Integrator {
|
public class JpaIntegrator implements Integrator {
|
||||||
private ListenerFactory jpaListenerFactory;
|
private ListenerFactory jpaListenerFactory;
|
||||||
private CallbackProcessor callbackProcessor;
|
private CallbackBuilder callbackBuilder;
|
||||||
private CallbackRegistryImpl callbackRegistry;
|
private CallbackRegistryImpl callbackRegistry;
|
||||||
|
|
||||||
private static final DuplicationStrategy JPA_DUPLICATION_STRATEGY = new JPADuplicationStrategy();
|
private static final DuplicationStrategy JPA_DUPLICATION_STRATEGY = new JPADuplicationStrategy();
|
||||||
|
@ -126,18 +126,14 @@ public class JpaIntegrator implements Integrator {
|
||||||
.getReflectionManager();
|
.getReflectionManager();
|
||||||
|
|
||||||
this.callbackRegistry = new CallbackRegistryImpl();
|
this.callbackRegistry = new CallbackRegistryImpl();
|
||||||
final Object beanManagerRef = sessionFactory.getSessionFactoryOptions().getBeanManagerReference();
|
this.jpaListenerFactory = ListenerFactoryBuilder.buildListenerFactory( sessionFactory.getSessionFactoryOptions() );
|
||||||
this.jpaListenerFactory = beanManagerRef == null
|
this.callbackBuilder = new CallbackBuilderLegacyImpl( jpaListenerFactory, reflectionManager );
|
||||||
? new StandardListenerFactory()
|
|
||||||
: buildBeanManagerListenerFactory( beanManagerRef );
|
|
||||||
this.callbackProcessor = new LegacyCallbackProcessor( jpaListenerFactory, reflectionManager );
|
|
||||||
|
|
||||||
for ( PersistentClass persistentClass : metadata.getEntityBindings() ) {
|
for ( PersistentClass persistentClass : metadata.getEntityBindings() ) {
|
||||||
if ( persistentClass.getClassName() == null ) {
|
if ( persistentClass.getClassName() == null ) {
|
||||||
// we can have non java class persisted by hibernate
|
// we can have non java class persisted by hibernate
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
callbackProcessor.processCallbacksForEntity( persistentClass.getClassName(), callbackRegistry );
|
callbackBuilder.buildCallbacksForEntity( persistentClass.getClassName(), callbackRegistry );
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( EventType eventType : EventType.values() ) {
|
for ( EventType eventType : EventType.values() ) {
|
||||||
|
@ -191,8 +187,8 @@ public class JpaIntegrator implements Integrator {
|
||||||
if ( callbackRegistry != null ) {
|
if ( callbackRegistry != null ) {
|
||||||
callbackRegistry.release();
|
callbackRegistry.release();
|
||||||
}
|
}
|
||||||
if ( callbackProcessor != null ) {
|
if ( callbackBuilder != null ) {
|
||||||
callbackProcessor.release();
|
callbackBuilder.release();
|
||||||
}
|
}
|
||||||
if ( jpaListenerFactory != null ) {
|
if ( jpaListenerFactory != null ) {
|
||||||
jpaListenerFactory.release();
|
jpaListenerFactory.release();
|
||||||
|
|
|
@ -9,12 +9,29 @@ package org.hibernate.jpa.event.spi.jpa;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a JPA event callback.
|
* Represents a JPA event callback (the method).
|
||||||
|
* <p/>
|
||||||
|
* Generally there are 2 flavors of this; either an annotated method on the entity itself
|
||||||
|
* or an annotated method on a separate "listener" class. This contract unifies both of
|
||||||
|
* these cases.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:kabir.khan@jboss.org">Kabir Khan</a>
|
* @author <a href="mailto:kabir.khan@jboss.org">Kabir Khan</a>
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface Callback extends Serializable {
|
public interface Callback extends Serializable {
|
||||||
|
/**
|
||||||
|
* Is this callback active (will it do anything)?
|
||||||
|
*
|
||||||
|
* @return {@code true} if the callback is active, {@code false} otherwise.
|
||||||
|
*
|
||||||
|
* @deprecated I can actually find no usages of this method and have no idea
|
||||||
|
* why it is here :)
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
boolean isActive();
|
||||||
|
|
||||||
|
CallbackType getCallbackType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contract for performing the callback
|
* Contract for performing the callback
|
||||||
*
|
*
|
||||||
|
@ -22,12 +39,5 @@ public interface Callback extends Serializable {
|
||||||
*
|
*
|
||||||
* @return Did a callback actually happen?
|
* @return Did a callback actually happen?
|
||||||
*/
|
*/
|
||||||
public boolean performCallback(Object entity);
|
boolean performCallback(Object entity);
|
||||||
|
|
||||||
/**
|
|
||||||
* Is this callback active (will it do anything)?
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public boolean isActive();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.jpa.event.spi.jpa;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contract for walking an entity hierarchy and building a list of JPA callbacks
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface CallbackBuilder {
|
||||||
|
/**
|
||||||
|
* Represents the target of JPA callback registrations as part the EntityCallbackBuilder
|
||||||
|
*/
|
||||||
|
interface CallbackRegistrar extends CallbackRegistry {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the callback against the given entity.
|
||||||
|
*
|
||||||
|
* @param entityClass The entity Class to register the Callbacks against
|
||||||
|
* @param callbacks The Callbacks to register against the given entity Class
|
||||||
|
*/
|
||||||
|
void registerCallbacks(Class entityClass, Callback[] callbacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
void buildCallbacksForEntity(String entityName, CallbackRegistrar callbackRegistrar);
|
||||||
|
|
||||||
|
void release();
|
||||||
|
}
|
|
@ -12,19 +12,52 @@ import java.io.Serializable;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface CallbackRegistry extends Serializable {
|
public interface CallbackRegistry extends Serializable {
|
||||||
|
/**
|
||||||
|
* Do we have any registered callbacks of the given type for the given entity?
|
||||||
|
*
|
||||||
|
* @param entityClass The entity Class to check against
|
||||||
|
* @param callbackType The type of callback to look for
|
||||||
|
*
|
||||||
|
* @return {@code true} indicates there are already registered callbacks of
|
||||||
|
* that type for that class; {@code false} indicates there are not.
|
||||||
|
*/
|
||||||
|
boolean hasRegisteredCallbacks(Class entityClass, CallbackType callbackType);
|
||||||
|
|
||||||
void preCreate(Object entity);
|
void preCreate(Object entity);
|
||||||
boolean hasPostCreateCallbacks(Class entityClass);
|
|
||||||
void postCreate(Object entity);
|
void postCreate(Object entity);
|
||||||
|
|
||||||
boolean preUpdate(Object entity);
|
boolean preUpdate(Object entity);
|
||||||
boolean hasPostUpdateCallbacks(Class entityClass);
|
|
||||||
void postUpdate(Object entity);
|
void postUpdate(Object entity);
|
||||||
|
|
||||||
void preRemove(Object entity);
|
void preRemove(Object entity);
|
||||||
boolean hasPostRemoveCallbacks(Class entityClass);
|
|
||||||
void postRemove(Object entity);
|
void postRemove(Object entity);
|
||||||
|
|
||||||
boolean postLoad(Object entity);
|
boolean postLoad(Object entity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #hasRegisteredCallbacks(Class, CallbackType)} instead passing
|
||||||
|
* {@link CallbackType#POST_PERSIST}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
boolean hasPostCreateCallbacks(Class entityClass);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #hasRegisteredCallbacks(Class, CallbackType)} instead passing
|
||||||
|
* {@link CallbackType#POST_UPDATE}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
boolean hasPostUpdateCallbacks(Class entityClass);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #hasRegisteredCallbacks(Class, CallbackType)} instead passing
|
||||||
|
* {@link CallbackType#POST_REMOVE}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
boolean hasPostRemoveCallbacks(Class entityClass);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #hasRegisteredCallbacks(Class, CallbackType)} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
boolean hasRegisteredCallbacks(Class entityClass, Class annotationClass);
|
boolean hasRegisteredCallbacks(Class entityClass, Class annotationClass);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,9 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.jpa.event.internal.jpa;
|
package org.hibernate.jpa.event.spi.jpa;
|
||||||
|
|
||||||
import org.hibernate.jpa.event.internal.core.HibernateEntityManagerEventListener;
|
import org.hibernate.jpa.event.internal.core.HibernateEntityManagerEventListener;
|
||||||
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contract for injecting the registry of Callbacks into event listeners.
|
* Contract for injecting the registry of Callbacks into event listeners.
|
||||||
|
@ -21,5 +20,5 @@ public interface CallbackRegistryConsumer extends HibernateEntityManagerEventLis
|
||||||
*
|
*
|
||||||
* @param callbackRegistry The CallbackRegistry
|
* @param callbackRegistry The CallbackRegistry
|
||||||
*/
|
*/
|
||||||
public void injectCallbackRegistry(CallbackRegistry callbackRegistry);
|
void injectCallbackRegistry(CallbackRegistry callbackRegistry);
|
||||||
}
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.jpa.event.spi.jpa;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import javax.persistence.PostLoad;
|
||||||
|
import javax.persistence.PostPersist;
|
||||||
|
import javax.persistence.PostRemove;
|
||||||
|
import javax.persistence.PostUpdate;
|
||||||
|
import javax.persistence.PrePersist;
|
||||||
|
import javax.persistence.PreRemove;
|
||||||
|
import javax.persistence.PreUpdate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public enum CallbackType {
|
||||||
|
PRE_UPDATE( PreUpdate.class ),
|
||||||
|
POST_UPDATE( PostUpdate.class ),
|
||||||
|
PRE_PERSIST( PrePersist.class ),
|
||||||
|
POST_PERSIST( PostPersist.class ),
|
||||||
|
PRE_REMOVE( PreRemove.class ),
|
||||||
|
POST_REMOVE( PostRemove.class ),
|
||||||
|
POST_LOAD( PostLoad.class )
|
||||||
|
;
|
||||||
|
|
||||||
|
private Class<? extends Annotation> callbackAnnotation;
|
||||||
|
|
||||||
|
CallbackType(Class<? extends Annotation> callbackAnnotation) {
|
||||||
|
this.callbackAnnotation = callbackAnnotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<? extends Annotation> getCallbackAnnotation() {
|
||||||
|
return callbackAnnotation;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.jpa.event.spi.jpa;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates access to the listener instance for listener callbacks
|
||||||
|
* ({@link javax.persistence.EntityListeners}).
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface Listener<T> {
|
||||||
|
T getListener();
|
||||||
|
}
|
|
@ -7,12 +7,16 @@
|
||||||
package org.hibernate.jpa.event.spi.jpa;
|
package org.hibernate.jpa.event.spi.jpa;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory for building instances user-specified event listeners.
|
* Contract for building instances of JPA callback listener classes.
|
||||||
|
* <p/>
|
||||||
|
* Listener instances should be uniqued by Class such that the same instance is
|
||||||
|
* returned for any calls to {@link #buildListener} with the same class.
|
||||||
|
*
|
||||||
|
* @see javax.persistence.EntityListeners
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface ListenerFactory {
|
public interface ListenerFactory {
|
||||||
public <T> T buildListener(Class<T> listenerClass);
|
<T> Listener<T> buildListener(Class<T> listenerClass);
|
||||||
|
void release();
|
||||||
public void release();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.jpa.event.spi.jpa;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.boot.spi.SessionFactoryOptions;
|
||||||
|
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||||
|
import org.hibernate.engine.config.spi.StandardConverters;
|
||||||
|
import org.hibernate.jpa.AvailableSettings;
|
||||||
|
import org.hibernate.jpa.event.internal.jpa.ListenerFactoryStandardImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder for ListenerFactory based on configuration options
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class ListenerFactoryBuilder {
|
||||||
|
|
||||||
|
public static ListenerFactory buildListenerFactory(SessionFactoryOptions options) {
|
||||||
|
final Object beanManagerRef = options.getBeanManagerReference();
|
||||||
|
if ( beanManagerRef == null ) {
|
||||||
|
return new ListenerFactoryStandardImpl();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final boolean delayAccessToCdi = options.getServiceRegistry()
|
||||||
|
.getService( ConfigurationService.class )
|
||||||
|
.getSetting( AvailableSettings.DELAY_CDI_ACCESS, StandardConverters.BOOLEAN, false );
|
||||||
|
if ( delayAccessToCdi ) {
|
||||||
|
return buildDelayedBeanManagerListenerFactory( beanManagerRef );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return buildStandardBeanManagerListenerFactory( beanManagerRef );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static final String CDI_LISTENER_FACTORY_STANDARD_CLASS = "org.hibernate.jpa.event.internal.jpa.ListenerFactoryBeanManagerStandardImpl";
|
||||||
|
private static final String CDI_LISTENER_FACTORY_DELAYED_CLASS = "org.hibernate.jpa.event.internal.jpa.ListenerFactoryBeanManagerDelayedImpl";
|
||||||
|
private static final String CDI_LISTENER_FACTORY_METHOD_NAME = "fromBeanManagerReference";
|
||||||
|
|
||||||
|
|
||||||
|
private static ListenerFactory buildStandardBeanManagerListenerFactory(Object beanManagerRef) {
|
||||||
|
return buildBeanManagerListenerFactory( beanManagerRef, CDI_LISTENER_FACTORY_STANDARD_CLASS );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ListenerFactory buildDelayedBeanManagerListenerFactory(Object beanManagerRef) {
|
||||||
|
return buildBeanManagerListenerFactory( beanManagerRef, CDI_LISTENER_FACTORY_DELAYED_CLASS );
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static ListenerFactory buildBeanManagerListenerFactory(
|
||||||
|
Object beanManagerRef,
|
||||||
|
String listenerClass) {
|
||||||
|
try {
|
||||||
|
// specifically using our ClassLoader here...
|
||||||
|
final Class beanManagerListenerFactoryClass = ListenerFactoryBuilder.class.getClassLoader()
|
||||||
|
.loadClass( listenerClass );
|
||||||
|
final Method beanManagerListenerFactoryBuilderMethod = beanManagerListenerFactoryClass.getMethod(
|
||||||
|
CDI_LISTENER_FACTORY_METHOD_NAME,
|
||||||
|
Object.class
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return (ListenerFactory) beanManagerListenerFactoryBuilderMethod.invoke( null, beanManagerRef );
|
||||||
|
}
|
||||||
|
catch (InvocationTargetException e) {
|
||||||
|
throw e.getTargetException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException e) {
|
||||||
|
throw new HibernateException(
|
||||||
|
"Could not locate BeanManager ListenerFactory class [" + listenerClass + "] to handle CDI extensions",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch (HibernateException e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
catch (Throwable e) {
|
||||||
|
throw new HibernateException(
|
||||||
|
"Could not access BeanManager ListenerFactory class [" + listenerClass + "] to handle CDI extensions",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016, 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
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
|
@ -18,9 +42,13 @@ import org.jboss.weld.bootstrap.api.Environments;
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public abstract class BaseCDIIntegrationTest extends BaseEntityManagerFunctionalTestCase {
|
public abstract class BaseCdiIntegrationTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
private TestContainer testContainer;
|
private TestContainer testContainer;
|
||||||
|
|
||||||
|
public TestContainer getTestContainer() {
|
||||||
|
return testContainer;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected void addConfigOptions(Map options) {
|
protected void addConfigOptions(Map options) {
|
|
@ -1,3 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016, 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
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
|
@ -6,9 +30,10 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.jpa.test.cdi;
|
package org.hibernate.jpa.test.cdi;
|
||||||
|
|
||||||
import javax.enterprise.context.spi.CreationalContext;
|
import java.text.SimpleDateFormat;
|
||||||
import javax.enterprise.inject.spi.AnnotatedType;
|
import java.util.ArrayList;
|
||||||
import javax.enterprise.inject.spi.InjectionTarget;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.EntityListeners;
|
import javax.persistence.EntityListeners;
|
||||||
|
@ -16,10 +41,6 @@ import javax.persistence.EntityManager;
|
||||||
import javax.persistence.Id;
|
import javax.persistence.Id;
|
||||||
import javax.persistence.PrePersist;
|
import javax.persistence.PrePersist;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -28,7 +49,7 @@ import static org.junit.Assert.assertEquals;
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class BasicCDITest extends BaseCDIIntegrationTest {
|
public class BasicCdiTest extends BaseCdiIntegrationTest {
|
||||||
private static int count;
|
private static int count;
|
||||||
|
|
||||||
@Override
|
@Override
|
|
@ -0,0 +1,427 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016, 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.jpa.test.cdi;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.el.ELResolver;
|
||||||
|
import javax.el.ExpressionFactory;
|
||||||
|
import javax.enterprise.context.spi.Context;
|
||||||
|
import javax.enterprise.context.spi.Contextual;
|
||||||
|
import javax.enterprise.context.spi.CreationalContext;
|
||||||
|
import javax.enterprise.inject.spi.AnnotatedField;
|
||||||
|
import javax.enterprise.inject.spi.AnnotatedMember;
|
||||||
|
import javax.enterprise.inject.spi.AnnotatedMethod;
|
||||||
|
import javax.enterprise.inject.spi.AnnotatedParameter;
|
||||||
|
import javax.enterprise.inject.spi.AnnotatedType;
|
||||||
|
import javax.enterprise.inject.spi.Bean;
|
||||||
|
import javax.enterprise.inject.spi.BeanAttributes;
|
||||||
|
import javax.enterprise.inject.spi.BeanManager;
|
||||||
|
import javax.enterprise.inject.spi.Decorator;
|
||||||
|
import javax.enterprise.inject.spi.Extension;
|
||||||
|
import javax.enterprise.inject.spi.InjectionPoint;
|
||||||
|
import javax.enterprise.inject.spi.InjectionTarget;
|
||||||
|
import javax.enterprise.inject.spi.InjectionTargetFactory;
|
||||||
|
import javax.enterprise.inject.spi.InterceptionType;
|
||||||
|
import javax.enterprise.inject.spi.Interceptor;
|
||||||
|
import javax.enterprise.inject.spi.ObserverMethod;
|
||||||
|
import javax.enterprise.inject.spi.ProducerFactory;
|
||||||
|
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 javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.hibernate.jpa.AvailableSettings;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class DelayedCdiTest extends BaseCdiIntegrationTest {
|
||||||
|
private BeanManagerImpl beanManager = new BeanManagerImpl();
|
||||||
|
|
||||||
|
private static int count;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class[] getCdiBeans() {
|
||||||
|
return new Class[] { EventQueue.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] { MyEntity.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addConfigOptions(Map options) {
|
||||||
|
options.put( AvailableSettings.DELAY_CDI_ACCESS, "true" );
|
||||||
|
super.addConfigOptions( options );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BeanManager getBeanManager() {
|
||||||
|
// this is the BeanManager used to bootstrap Hibernate. Here
|
||||||
|
// we want this to be our custom BeanManagerImpl
|
||||||
|
return beanManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void afterEntityManagerFactoryBuilt() {
|
||||||
|
beanManager.delegate = getTestContainer().getBeanManager( getTestContainer().getDeployment().getBeanDeploymentArchives().iterator().next() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 )
|
||||||
|
@Table(name = "my_entity")
|
||||||
|
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<Event> events;
|
||||||
|
|
||||||
|
public void addEvent(Event anEvent) {
|
||||||
|
if ( events == null ) {
|
||||||
|
events = new ArrayList<Event>();
|
||||||
|
}
|
||||||
|
events.add( anEvent );
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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() )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String now() {
|
||||||
|
return new SimpleDateFormat().format( new Date() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class BeanManagerImpl implements BeanManager {
|
||||||
|
private BeanManager delegate;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getReference(Bean<?> bean, Type beanType, CreationalContext<?> ctx) {
|
||||||
|
return getDelegate().getReference( bean, beanType, ctx );
|
||||||
|
}
|
||||||
|
|
||||||
|
private BeanManager getDelegate() {
|
||||||
|
if ( delegate == null ) {
|
||||||
|
throw new RuntimeException( "Real BeanManager not yet known" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getInjectableReference(InjectionPoint ij, CreationalContext<?> ctx) {
|
||||||
|
return getDelegate().getInjectableReference( ij, ctx );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> CreationalContext<T> createCreationalContext(Contextual<T> contextual) {
|
||||||
|
return getDelegate().createCreationalContext( contextual );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Bean<?>> getBeans(Type beanType, Annotation... qualifiers) {
|
||||||
|
return getDelegate().getBeans( beanType, qualifiers );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Bean<?>> getBeans(String name) {
|
||||||
|
return getDelegate().getBeans( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bean<?> getPassivationCapableBean(String id) {
|
||||||
|
return getDelegate().getPassivationCapableBean( id );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <X> Bean<? extends X> resolve(Set<Bean<? extends X>> beans) {
|
||||||
|
return getDelegate().resolve( beans );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validate(InjectionPoint injectionPoint) {
|
||||||
|
getDelegate().validate( injectionPoint );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fireEvent(Object event, Annotation... qualifiers) {
|
||||||
|
getDelegate().fireEvent( event, qualifiers );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> Set<ObserverMethod<? super T>> resolveObserverMethods(T event, Annotation... qualifiers) {
|
||||||
|
return getDelegate().resolveObserverMethods( event, qualifiers );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Decorator<?>> resolveDecorators(Set<Type> types, Annotation... qualifiers) {
|
||||||
|
return getDelegate().resolveDecorators( types, qualifiers );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Interceptor<?>> resolveInterceptors(InterceptionType type, Annotation... interceptorBindings) {
|
||||||
|
return getDelegate().resolveInterceptors( type, interceptorBindings );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isScope(Class<? extends Annotation> annotationType) {
|
||||||
|
return getDelegate().isScope( annotationType );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isNormalScope(Class<? extends Annotation> annotationType) {
|
||||||
|
return getDelegate().isNormalScope( annotationType );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPassivatingScope(Class<? extends Annotation> annotationType) {
|
||||||
|
return getDelegate().isPassivatingScope( annotationType );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isQualifier(Class<? extends Annotation> annotationType) {
|
||||||
|
return getDelegate().isQualifier( annotationType );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInterceptorBinding(Class<? extends Annotation> annotationType) {
|
||||||
|
return getDelegate().isInterceptorBinding( annotationType );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isStereotype(Class<? extends Annotation> annotationType) {
|
||||||
|
return getDelegate().isStereotype( annotationType );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Annotation> getInterceptorBindingDefinition(Class<? extends Annotation> bindingType) {
|
||||||
|
return getDelegate().getInterceptorBindingDefinition( bindingType );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Annotation> getStereotypeDefinition(Class<? extends Annotation> stereotype) {
|
||||||
|
return getDelegate().getStereotypeDefinition( stereotype );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areQualifiersEquivalent(Annotation qualifier1, Annotation qualifier2) {
|
||||||
|
return getDelegate().areQualifiersEquivalent( qualifier1, qualifier2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areInterceptorBindingsEquivalent(Annotation interceptorBinding1, Annotation interceptorBinding2) {
|
||||||
|
return getDelegate().areInterceptorBindingsEquivalent( interceptorBinding1, interceptorBinding2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getQualifierHashCode(Annotation qualifier) {
|
||||||
|
return getDelegate().getQualifierHashCode( qualifier );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getInterceptorBindingHashCode(Annotation interceptorBinding) {
|
||||||
|
return getDelegate().getInterceptorBindingHashCode( interceptorBinding );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Context getContext(Class<? extends Annotation> scopeType) {
|
||||||
|
return getDelegate().getContext( scopeType );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ELResolver getELResolver() {
|
||||||
|
return getDelegate().getELResolver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExpressionFactory wrapExpressionFactory(ExpressionFactory expressionFactory) {
|
||||||
|
return getDelegate().wrapExpressionFactory( expressionFactory );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> AnnotatedType<T> createAnnotatedType(Class<T> type) {
|
||||||
|
return getDelegate().createAnnotatedType( type );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> InjectionTarget<T> createInjectionTarget(AnnotatedType<T> type) {
|
||||||
|
return getDelegate().createInjectionTarget( type );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> InjectionTargetFactory<T> getInjectionTargetFactory(AnnotatedType<T> annotatedType) {
|
||||||
|
return getDelegate().getInjectionTargetFactory( annotatedType );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <X> ProducerFactory<X> getProducerFactory(AnnotatedField<? super X> field) {
|
||||||
|
return getDelegate().getProducerFactory( field );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <X> ProducerFactory<X> getProducerFactory(AnnotatedMethod<? super X> method) {
|
||||||
|
return getDelegate().getProducerFactory( method );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> BeanAttributes<T> createBeanAttributes(AnnotatedType<T> type) {
|
||||||
|
return getDelegate().createBeanAttributes( type );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BeanAttributes<?> createBeanAttributes(AnnotatedMember<?> type) {
|
||||||
|
return getDelegate().createBeanAttributes( type );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> Bean<T> createBean(BeanAttributes<T> attributes, Class<T> beanClass, InjectionTargetFactory<T> injectionTargetFactory) {
|
||||||
|
return getDelegate().createBean( attributes, beanClass, injectionTargetFactory );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> Bean<T> createBean(BeanAttributes<T> attributes, Class<?> beanClass, ProducerFactory<T> producerFactory) {
|
||||||
|
return getDelegate().createBean( attributes, beanClass, producerFactory );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InjectionPoint createInjectionPoint(AnnotatedField<?> field) {
|
||||||
|
return getDelegate().createInjectionPoint( field );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InjectionPoint createInjectionPoint(AnnotatedParameter<?> parameter) {
|
||||||
|
return getDelegate().createInjectionPoint( parameter );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Extension> T getExtension(Class<T> extensionClass) {
|
||||||
|
return getDelegate().getExtension( extensionClass );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue