HHH-10477 - Setting to allow delayed access to CDI
This commit is contained in:
parent
95ed41b445
commit
6732e04058
|
@ -555,4 +555,12 @@ public interface AvailableSettings {
|
|||
* Used to pass along the name of the persistence unit.
|
||||
*/
|
||||
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";
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ import org.hibernate.annotations.common.reflection.XClass;
|
|||
import org.hibernate.annotations.common.reflection.XMethod;
|
||||
import org.hibernate.jpa.event.spi.jpa.Callback;
|
||||
import org.hibernate.jpa.event.spi.jpa.CallbackType;
|
||||
import org.hibernate.jpa.event.spi.jpa.EntityCallbackBuilder;
|
||||
import org.hibernate.jpa.event.spi.jpa.CallbackBuilder;
|
||||
import org.hibernate.jpa.event.spi.jpa.ListenerFactory;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
@ -37,13 +37,13 @@ import org.jboss.logging.Logger;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class EntityCallbackBuilderLegacyImpl implements EntityCallbackBuilder {
|
||||
private static final Logger log = Logger.getLogger( EntityCallbackBuilderLegacyImpl.class );
|
||||
public class CallbackBuilderLegacyImpl implements CallbackBuilder {
|
||||
private static final Logger log = Logger.getLogger( CallbackBuilderLegacyImpl.class );
|
||||
|
||||
private final ListenerFactory jpaListenerFactory;
|
||||
private final ReflectionManager reflectionManager;
|
||||
|
||||
public EntityCallbackBuilderLegacyImpl(ListenerFactory jpaListenerFactory, ReflectionManager reflectionManager) {
|
||||
public CallbackBuilderLegacyImpl(ListenerFactory jpaListenerFactory, ReflectionManager reflectionManager) {
|
||||
this.jpaListenerFactory = jpaListenerFactory;
|
||||
this.reflectionManager = reflectionManager;
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -12,7 +12,7 @@ import javax.persistence.PersistenceException;
|
|||
import org.hibernate.jpa.event.spi.jpa.Callback;
|
||||
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
|
||||
import org.hibernate.jpa.event.spi.jpa.CallbackType;
|
||||
import org.hibernate.jpa.event.spi.jpa.EntityCallbackBuilder;
|
||||
import org.hibernate.jpa.event.spi.jpa.CallbackBuilder;
|
||||
|
||||
/**
|
||||
* Keep track of all lifecycle callbacks and listeners for a given persistence unit
|
||||
|
@ -21,7 +21,7 @@ import org.hibernate.jpa.event.spi.jpa.EntityCallbackBuilder;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "serial"})
|
||||
public class CallbackRegistryImpl implements CallbackRegistry, EntityCallbackBuilder.CallbackRegistrar {
|
||||
public class CallbackRegistryImpl implements CallbackRegistry, CallbackBuilder.CallbackRegistrar {
|
||||
private HashMap<Class, Callback[]> preCreates = new HashMap<Class, Callback[]>();
|
||||
private HashMap<Class, Callback[]> postCreates = new HashMap<Class, Callback[]>();
|
||||
private HashMap<Class, Callback[]> preRemoves = new HashMap<Class, Callback[]>();
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* @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 JpaIntegrator, 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
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,6 +18,8 @@ import org.hibernate.jpa.event.spi.jpa.ExtendedBeanManager;
|
|||
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. Further, this
|
||||
* implementation leverages the ExtendedBeanManager contract to delay CDI calls.
|
||||
|
@ -25,7 +27,9 @@ import org.hibernate.jpa.event.spi.jpa.ListenerFactory;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ListenerFactoryBeanManagerLazyImpl implements ListenerFactory, ExtendedBeanManager.LifecycleListener {
|
||||
public class ListenerFactoryBeanManagerExtendedImpl implements ListenerFactory, ExtendedBeanManager.LifecycleListener {
|
||||
private static final Logger log = Logger.getLogger( ListenerFactoryBeanManagerExtendedImpl.class );
|
||||
|
||||
private final Map<Class,ListenerImpl> listenerMap = new ConcurrentHashMap<Class, ListenerImpl>();
|
||||
|
||||
/**
|
||||
|
@ -37,11 +41,11 @@ public class ListenerFactoryBeanManagerLazyImpl implements ListenerFactory, Exte
|
|||
* @return A instantiated ListenerFactoryBeanManagerImpl
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static ListenerFactoryBeanManagerLazyImpl fromBeanManagerReference(Object reference) {
|
||||
return new ListenerFactoryBeanManagerLazyImpl( (BeanManager) reference );
|
||||
public static ListenerFactoryBeanManagerExtendedImpl fromBeanManagerReference(Object reference) {
|
||||
return new ListenerFactoryBeanManagerExtendedImpl( (BeanManager) reference );
|
||||
}
|
||||
|
||||
public ListenerFactoryBeanManagerLazyImpl(BeanManager beanManager) {
|
||||
public ListenerFactoryBeanManagerExtendedImpl(BeanManager beanManager) {
|
||||
if ( !ExtendedBeanManager.class.isInstance( beanManager ) ) {
|
||||
throw new IllegalArgumentException(
|
||||
"Expecting BeanManager reference that implements optional ExtendedBeanManager contract : " +
|
||||
|
@ -49,6 +53,7 @@ public class ListenerFactoryBeanManagerLazyImpl implements ListenerFactory, Exte
|
|||
);
|
||||
}
|
||||
( (ExtendedBeanManager) beanManager ).registerLifecycleListener( this );
|
||||
log.debugf( "ExtendedBeanManager access requested to CDI BeanManager : " + beanManager );
|
||||
}
|
||||
|
||||
@Override
|
|
@ -16,11 +16,13 @@ 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 CDI-based
|
||||
* implementation works in the JPA standard prescribed manner.
|
||||
* <p/>
|
||||
* See {@link ListenerFactoryBeanManagerLazyImpl} for an alt implementation that
|
||||
* See {@link ListenerFactoryBeanManagerExtendedImpl} for an alt implementation that
|
||||
* is still JPA compliant, but that works based on delayed CDI calls. Works
|
||||
* on a non-CDI-defined CDI extension; we plan to propose this extension to the
|
||||
* CDI expert group for the next CDI iteration
|
||||
|
@ -29,8 +31,9 @@ import org.hibernate.jpa.event.spi.jpa.ListenerFactory;
|
|||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ListenerFactoryBeanManagerStandardImpl implements ListenerFactory {
|
||||
private final BeanManager beanManager;
|
||||
private static final Logger log = Logger.getLogger( ListenerFactoryBeanManagerStandardImpl.class );
|
||||
|
||||
private final BeanManager beanManager;
|
||||
private final Map<Class,ListenerImpl> listenerMap = new ConcurrentHashMap<Class, ListenerImpl>();
|
||||
|
||||
/**
|
||||
|
@ -48,6 +51,7 @@ public class ListenerFactoryBeanManagerStandardImpl implements ListenerFactory {
|
|||
|
||||
public ListenerFactoryBeanManagerStandardImpl(BeanManager beanManager) {
|
||||
this.beanManager = beanManager;
|
||||
log.debugf( "Standard access requested to CDI BeanManager : " + beanManager );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.jpa.event.spi;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
|
@ -40,11 +38,10 @@ import org.hibernate.jpa.event.internal.core.JpaPostLoadEventListener;
|
|||
import org.hibernate.jpa.event.internal.core.JpaPostUpdateEventListener;
|
||||
import org.hibernate.jpa.event.internal.core.JpaSaveEventListener;
|
||||
import org.hibernate.jpa.event.internal.core.JpaSaveOrUpdateEventListener;
|
||||
import org.hibernate.jpa.event.internal.jpa.EntityCallbackBuilderLegacyImpl;
|
||||
import org.hibernate.jpa.event.internal.jpa.CallbackBuilderLegacyImpl;
|
||||
import org.hibernate.jpa.event.spi.jpa.CallbackRegistryConsumer;
|
||||
import org.hibernate.jpa.event.internal.jpa.CallbackRegistryImpl;
|
||||
import org.hibernate.jpa.event.internal.jpa.ListenerFactoryStandardImpl;
|
||||
import org.hibernate.jpa.event.spi.jpa.EntityCallbackBuilder;
|
||||
import org.hibernate.jpa.event.spi.jpa.CallbackBuilder;
|
||||
import org.hibernate.jpa.event.spi.jpa.ListenerFactory;
|
||||
import org.hibernate.jpa.event.spi.jpa.ListenerFactoryBuilder;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
|
@ -58,7 +55,7 @@ import org.hibernate.service.spi.SessionFactoryServiceRegistry;
|
|||
*/
|
||||
public class JpaIntegrator implements Integrator {
|
||||
private ListenerFactory jpaListenerFactory;
|
||||
private EntityCallbackBuilder entityCallbackBuilder;
|
||||
private CallbackBuilder callbackBuilder;
|
||||
private CallbackRegistryImpl callbackRegistry;
|
||||
|
||||
private static final DuplicationStrategy JPA_DUPLICATION_STRATEGY = new JPADuplicationStrategy();
|
||||
|
@ -128,13 +125,13 @@ public class JpaIntegrator implements Integrator {
|
|||
|
||||
this.callbackRegistry = new CallbackRegistryImpl();
|
||||
this.jpaListenerFactory = ListenerFactoryBuilder.buildListenerFactory( sessionFactory.getSessionFactoryOptions() );
|
||||
this.entityCallbackBuilder = new EntityCallbackBuilderLegacyImpl( jpaListenerFactory, reflectionManager );
|
||||
this.callbackBuilder = new CallbackBuilderLegacyImpl( jpaListenerFactory, reflectionManager );
|
||||
for ( PersistentClass persistentClass : metadata.getEntityBindings() ) {
|
||||
if ( persistentClass.getClassName() == null ) {
|
||||
// we can have non java class persisted by hibernate
|
||||
continue;
|
||||
}
|
||||
entityCallbackBuilder.buildCallbacksForEntity( persistentClass.getClassName(), callbackRegistry );
|
||||
callbackBuilder.buildCallbacksForEntity( persistentClass.getClassName(), callbackRegistry );
|
||||
}
|
||||
|
||||
for ( EventType eventType : EventType.values() ) {
|
||||
|
@ -152,8 +149,8 @@ public class JpaIntegrator implements Integrator {
|
|||
if ( callbackRegistry != null ) {
|
||||
callbackRegistry.release();
|
||||
}
|
||||
if ( entityCallbackBuilder != null ) {
|
||||
entityCallbackBuilder.release();
|
||||
if ( callbackBuilder != null ) {
|
||||
callbackBuilder.release();
|
||||
}
|
||||
if ( jpaListenerFactory != null ) {
|
||||
jpaListenerFactory.release();
|
||||
|
|
|
@ -11,7 +11,7 @@ package org.hibernate.jpa.event.spi.jpa;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface EntityCallbackBuilder {
|
||||
public interface CallbackBuilder {
|
||||
/**
|
||||
* Represents the target of JPA callback registrations as part the EntityCallbackBuilder
|
||||
*/
|
|
@ -11,9 +11,14 @@ 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 {
|
||||
|
@ -24,32 +29,48 @@ public class ListenerFactoryBuilder {
|
|||
return new ListenerFactoryStandardImpl();
|
||||
}
|
||||
else if ( ExtendedBeanManager.class.isInstance( beanManagerRef ) ) {
|
||||
return buildLazyBeanManagerListenerFactory( beanManagerRef );
|
||||
return buildExtendedBeanManagerListenerFactory( beanManagerRef );
|
||||
}
|
||||
else {
|
||||
return buildStandardBeanManagerListenerFactory( beanManagerRef );
|
||||
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_CLASS = "org.hibernate.jpa.event.internal.jpa.ListenerFactoryBeanManagerStandardImpl";
|
||||
private static final String CDI_LISTENER_FACTORY_LAZY_CLASS = "org.hibernate.jpa.event.internal.jpa.ListenerFactoryBeanManagerLazyImpl";
|
||||
private static final String CDI_LISTENER_FACTORY_EXTENDED_CLASS = "org.hibernate.jpa.event.internal.jpa.ListenerFactoryBeanManagerExtendedImpl";
|
||||
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_CLASS );
|
||||
|
||||
private static ListenerFactory buildExtendedBeanManagerListenerFactory(Object beanManagerRef) {
|
||||
return buildBeanManagerListenerFactory( beanManagerRef, CDI_LISTENER_FACTORY_EXTENDED_CLASS );
|
||||
}
|
||||
|
||||
private static ListenerFactory buildLazyBeanManagerListenerFactory(Object beanManagerRef) {
|
||||
return buildBeanManagerListenerFactory( beanManagerRef, CDI_LISTENER_FACTORY_LAZY_CLASS );
|
||||
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 factoryClassName) {
|
||||
private static ListenerFactory buildBeanManagerListenerFactory(
|
||||
Object beanManagerRef,
|
||||
String listenerClass) {
|
||||
try {
|
||||
// specifically using our ClassLoader here...
|
||||
final Class beanManagerListenerFactoryClass = ListenerFactoryBuilder.class.getClassLoader()
|
||||
.loadClass( factoryClassName );
|
||||
.loadClass( listenerClass );
|
||||
final Method beanManagerListenerFactoryBuilderMethod = beanManagerListenerFactoryClass.getMethod(
|
||||
CDI_LISTENER_FACTORY_METHOD_NAME,
|
||||
Object.class
|
||||
|
@ -64,7 +85,7 @@ public class ListenerFactoryBuilder {
|
|||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
throw new HibernateException(
|
||||
"Could not locate BeanManager ListenerFactory class [" + factoryClassName + "] to handle CDI extensions",
|
||||
"Could not locate BeanManager ListenerFactory class [" + listenerClass + "] to handle CDI extensions",
|
||||
e
|
||||
);
|
||||
}
|
||||
|
@ -73,7 +94,7 @@ public class ListenerFactoryBuilder {
|
|||
}
|
||||
catch (Throwable e) {
|
||||
throw new HibernateException(
|
||||
"Could not access BeanManagerListenerFactory class to handle CDI extensions",
|
||||
"Could not access BeanManager ListenerFactory class [" + listenerClass + "] to handle CDI extensions",
|
||||
e
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,403 @@
|
|||
/*
|
||||
* 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 );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -52,7 +52,7 @@ import static org.junit.Assert.assertEquals;
|
|||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class LazyCdiTest extends BaseCdiIntegrationTest {
|
||||
public class ExtendedBeanManagerCdiTest extends BaseCdiIntegrationTest {
|
||||
ExtendedBeanManagerImpl extendedBeanManager = new ExtendedBeanManagerImpl();
|
||||
|
||||
private static int count;
|
Loading…
Reference in New Issue