/*
* 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.HibernateException;
import org.hibernate.jpa.event.spi.jpa.ExtendedBeanManager;
import org.hibernate.jpa.event.spi.jpa.Listener;
import org.hibernate.jpa.event.spi.jpa.ListenerFactory;
import org.jboss.logging.Logger;
/**
* CDI-based implementation of the ListenerFactory contract. Further, this
* implementation leverages the ExtendedBeanManager contract to delay CDI calls.
*
* @author Steve Ebersole
*/
@SuppressWarnings("unused")
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>();
/**
* 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 ListenerFactoryBeanManagerExtendedImpl fromBeanManagerReference(Object reference) {
if ( !ExtendedBeanManager.class.isInstance( reference ) ) {
throw new IllegalArgumentException(
"Expecting BeanManager reference that implements optional ExtendedBeanManager contract : " +
reference
);
}
return new ListenerFactoryBeanManagerExtendedImpl( (ExtendedBeanManager) reference );
}
public ListenerFactoryBeanManagerExtendedImpl(ExtendedBeanManager beanManager) {
beanManager.registerLifecycleListener( this );
log.debugf( "ExtendedBeanManager 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();
}
@Override
public void beanManagerInitialized(BeanManager beanManager) {
for ( ListenerImpl listenerImpl : listenerMap.values() ) {
listenerImpl.initialize( beanManager );
}
}
private static 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;
}
public void initialize(BeanManager beanManager) {
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 ) {
throw new HibernateException( "CDI not initialized as expected" );
}
return listenerInstance;
}
public void release() {
if ( !initialized ) {
// log
return;
}
injectionTarget.preDestroy( listenerInstance );
injectionTarget.dispose( listenerInstance );
creationalContext.release();
}
}
}