HHH-11259 - Improved CDI support including support for other types of managed beans;

HHH-12133 - Create ManagedBeanRegistry and ManagedBean;
HHH-12134 - Convert entity listener CDI support to use ManagedBean/MenagedBeanRepository

Initial support for named CDI beans and the option to not cache bean references
This commit is contained in:
Steve Ebersole 2017-12-14 11:36:54 -06:00
parent 9f50157a60
commit ddc1f03abc
19 changed files with 565 additions and 96 deletions

View File

@ -755,10 +755,20 @@ public final class SessionFactoryImpl implements SessionFactoryImplementor {
settings.getMultiTableBulkIdStrategy().release( serviceRegistry.getService( JdbcServices.class ), buildLocalConnectionAccess() );
cacheAccess.close();
metamodel.close();
// NOTE : the null checks below handle cases where close is called from
// a failed attempt to create the SessionFactory
if ( cacheAccess != null ) {
cacheAccess.close();
}
if ( metamodel != null ) {
metamodel.close();
}
if ( queryPlanCache != null ) {
queryPlanCache.cleanup();
}
if ( delayedDropAction != null ) {
delayedDropAction.perform( serviceRegistry );

View File

@ -23,6 +23,7 @@ import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.jmx.spi.JmxService;
import org.hibernate.service.Service;
import org.hibernate.service.spi.Manageable;
import org.hibernate.service.spi.OptionallyManageable;
import org.hibernate.service.spi.Stoppable;
/**
@ -106,6 +107,13 @@ public class JmxServiceImpl implements JmxService, Stoppable {
@Override
public void registerService(Manageable service, Class<? extends Service> serviceRole) {
if ( OptionallyManageable.class.isInstance( service ) ) {
for ( Manageable realManageable : ( (OptionallyManageable) service ).getRealManageables() ) {
registerService( realManageable,serviceRole );
}
return;
}
final String domain = service.getManagementDomain() == null
? AvailableSettings.JMX_DEFAULT_OBJ_NAME_DOMAIN
: service.getManagementDomain();

View File

@ -23,7 +23,7 @@ public interface JmxService extends Service {
* @param service The manageable service
* @param serviceRole The service's role.
*/
public void registerService(Manageable service, Class<? extends Service> serviceRole);
void registerService(Manageable service, Class<? extends Service> serviceRole);
/**
* Registers the given {@code mBean} under the given {@code objectName}
@ -31,5 +31,5 @@ public interface JmxService extends Service {
* @param objectName The name under which to register the MBean
* @param mBean The MBean to register
*/
public void registerMBean(ObjectName objectName, Object mBean);
void registerMBean(ObjectName objectName, Object mBean);
}

View File

@ -75,6 +75,7 @@ public class CallbackBuilderLegacyImpl implements CallbackBuilder {
}
}
@SuppressWarnings({"unchecked", "WeakerAccess"})
public Callback[] resolveCallbacks(XClass beanClass, CallbackType callbackType, ReflectionManager reflectionManager) {
List<Callback> callbacks = new ArrayList<>();
List<String> callbacksMethodNames = new ArrayList<>();
@ -162,7 +163,7 @@ public class CallbackBuilderLegacyImpl implements CallbackBuilder {
//overridden method, remove the superclass overridden method
if ( callback == null ) {
callback = new ListenerCallback(
managedBeanRegistry.getBean( listener ),
managedBeanRegistry.getBean( listener, true ),
method,
callbackType
);

View File

@ -26,7 +26,7 @@ public interface BeansMessageLogger {
/**
* *The* BeansMessageLogger instance
*/
BeansMessageLogger CDI_LOGGER = Logger.getMessageLogger(
BeansMessageLogger BEANS_LOGGER = Logger.getMessageLogger(
BeansMessageLogger.class,
"org.hibernate.orm.beans"
);

View File

@ -6,56 +6,142 @@
*/
package org.hibernate.resource.beans.internal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.Map;
import org.hibernate.resource.beans.spi.ManagedBean;
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
import org.hibernate.service.spi.Configurable;
import org.hibernate.service.spi.Manageable;
import org.hibernate.service.spi.OptionallyManageable;
import org.hibernate.service.spi.ServiceRegistryAwareService;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.service.spi.Startable;
import org.hibernate.service.spi.Stoppable;
import org.jboss.logging.Logger;
/**
* A ManagedBeanRegistry implementation that can delegate to multiple
* other ManagedBeanRegistry instances, until one can handle the given call.
* A ManagedBeanRegistry that supports a single primary ManagedBeanRegistry
* delegate falling back to {@link ManagedBeanRegistryDirectImpl} for direct
* instantiation (no DI).
*
* Note too that it supports all of the optional Service contracts and delegates
* them to the primary if the primary also implements that particular contract.
*
* @author Steve Ebersole
*/
public class CompositeManagedBeanRegistry implements ManagedBeanRegistry {
public class CompositeManagedBeanRegistry
implements ManagedBeanRegistry, Startable, Stoppable, Configurable, ServiceRegistryAwareService, OptionallyManageable {
private static final Logger log = Logger.getLogger( CompositeManagedBeanRegistry.class );
private List<ManagedBeanRegistry> delegates;
private final ManagedBeanRegistry primaryRegistry;
private final ManagedBeanRegistryDirectImpl fallback = new ManagedBeanRegistryDirectImpl();
public void addDelegate(ManagedBeanRegistry beanRegistry) {
if ( delegates == null ) {
delegates = new ArrayList<>();
}
delegates.add( beanRegistry );
}
@Override
public <T> ManagedBean<T> getBean(Class<T> beanClass) {
return tryEachRegistry( registry -> registry.getBean( beanClass ) );
public CompositeManagedBeanRegistry(ManagedBeanRegistry primaryRegistry) {
this.primaryRegistry = primaryRegistry;
}
@Override
public <T> ManagedBean<T> getBean(String beanName, Class<T> contract) {
return tryEachRegistry( registry -> registry.getBean( beanName, contract ) );
}
private <T> ManagedBean<T> tryEachRegistry(Function<ManagedBeanRegistry, ManagedBean<T>> delegateAction) {
if ( delegates != null ) {
for ( ManagedBeanRegistry delegate : delegates ) {
ManagedBean<T> bean = null;
public <T> ManagedBean<T> getBean(Class<T> beanClass, boolean shouldRegistryManageLifecycle) {
if ( primaryRegistry != null ) {
try {
bean = delegateAction.apply( delegate );
}
catch (Exception ignore) {
}
final ManagedBean<T> bean = primaryRegistry.getBean( beanClass, shouldRegistryManageLifecycle );
if ( bean != null ) {
return bean;
}
}
catch (Exception ignore) {
log.debugf(
"Error obtaining ManagedBean [%s] from registry [%s] - using fallback registry",
beanClass.getName(),
primaryRegistry
);
}
}
return delegateAction.apply( ManagedBeanRegistryDirectImpl.INSTANCE );
return fallback.getBean( beanClass, shouldRegistryManageLifecycle );
}
@Override
public <T> ManagedBean<T> getBean(String beanName, Class<T> beanContract, boolean shouldRegistryManageLifecycle) {
if ( primaryRegistry != null ) {
try {
final ManagedBean<T> bean = primaryRegistry.getBean( beanName, beanContract,shouldRegistryManageLifecycle );
if ( bean != null ) {
return bean;
}
}
catch (Exception ignore) {
log.debugf(
"Error obtaining ManagedBean [%s : %s] from registry [%s] - using fallback registry",
beanName,
beanContract.getName(),
primaryRegistry
);
}
}
return fallback.getBean( beanName, beanContract,shouldRegistryManageLifecycle );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Optional delegation
@Override
public void start() {
if ( primaryRegistry == null ) {
return;
}
if ( Startable.class.isInstance( primaryRegistry ) ) {
Startable.class.cast( primaryRegistry ).start();
}
}
@Override
public void configure(Map configurationValues) {
if ( primaryRegistry == null ) {
return;
}
if ( Configurable.class.isInstance( primaryRegistry ) ) {
Configurable.class.cast( primaryRegistry ).configure( configurationValues );
}
}
@Override
public void injectServices(ServiceRegistryImplementor serviceRegistry) {
if ( primaryRegistry == null ) {
return;
}
if ( ServiceRegistryAwareService.class.isInstance( primaryRegistry ) ) {
ServiceRegistryAwareService.class.cast( primaryRegistry ).injectServices( serviceRegistry );
}
}
@Override
public List<Manageable> getRealManageables() {
if ( primaryRegistry != null ) {
if ( Manageable.class.isInstance( primaryRegistry ) ) {
return Collections.singletonList( (Manageable) primaryRegistry );
}
}
return Collections.emptyList();
}
@Override
public void stop() {
if ( primaryRegistry == null ) {
return;
}
if ( Stoppable.class.isInstance( primaryRegistry ) ) {
Stoppable.class.cast( primaryRegistry ).stop();
}
}
}

View File

@ -0,0 +1,42 @@
/*
* 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.resource.beans.internal;
import java.util.Set;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
/**
* @author Steve Ebersole
*/
public class Helper {
/**
* Singleton access
*/
public static final Helper INSTANCE = new Helper();
private Helper() {
}
@SuppressWarnings("unchecked")
public <T> Bean<T> getNamedBean(String beanName, Class<T> beanContract, BeanManager beanManager) {
Set<Bean<?>> beans = beanManager.getBeans( beanContract, new NamedBeanQualifier( beanName ) );
if ( beans.isEmpty() ) {
throw new IllegalArgumentException(
"BeanManager returned no matching beans: name = " + beanName + "; contract = " + beanContract.getName()
);
}
if ( beans.size() > 1 ) {
throw new IllegalArgumentException(
"BeanManager returned multiple matching beans: name = " + beanName + "; contract = " + beanContract.getName()
);
}
return (Bean<T>) beans.iterator().next();
}
}

View File

@ -23,6 +23,9 @@ import org.hibernate.service.ServiceRegistry;
/**
* Utility class for helping deal with the reflection calls relating to CDI.
*
* We need to to avoid statically linking CDI classed into the ClassLoader which
* would lead to errors if CDI is not available on the classpath.
*
* @author Steve Ebersole
*/
public class ManagedBeanRegistryCdiBuilder {

View File

@ -6,8 +6,10 @@
*/
package org.hibernate.resource.beans.internal;
import java.util.Set;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.InjectionTarget;
@ -32,12 +34,17 @@ public class ManagedBeanRegistryCdiDelayedImpl extends AbstractManagedBeanRegist
private ManagedBeanRegistryCdiDelayedImpl(BeanManager beanManager) {
this.beanManager = beanManager;
log.debugf( "Delayed access requested to CDI BeanManager : " + beanManager );
log.debugf( "Delayed access requested to CDI BeanManager" );
}
@Override
protected <T> ManagedBean<T> createBean(Class<T> beanClass) {
return new ManagedBeanImpl<>( beanClass );
}
@Override
protected <T> ManagedBean<T> createBean(String beanName, Class<T> beanContract) {
return new ManagedBeanImpl<>( beanContract );
return new NamedManagedBeanImpl<>( beanName, beanContract );
}
private class ManagedBeanImpl<T> implements ManagedBean<T> {
@ -46,10 +53,10 @@ public class ManagedBeanRegistryCdiDelayedImpl extends AbstractManagedBeanRegist
private boolean initialized = false;
private InjectionTarget<T> injectionTarget;
private CreationalContext<T> creationalContext;
private CreationalContext<T> creationContext;
private T beanInstance;
public ManagedBeanImpl(Class<T> beanClass) {
ManagedBeanImpl(Class<T> beanClass) {
this.beanClass = beanClass;
}
@ -71,10 +78,10 @@ public class ManagedBeanRegistryCdiDelayedImpl extends AbstractManagedBeanRegist
final AnnotatedType<T> annotatedType = beanManager.createAnnotatedType( beanClass );
this.injectionTarget = beanManager.createInjectionTarget( annotatedType );
this.creationalContext = beanManager.createCreationalContext( null );
this.creationContext = beanManager.createCreationalContext( null );
this.beanInstance = injectionTarget.produce( creationalContext );
injectionTarget.inject( this.beanInstance, creationalContext );
this.beanInstance = injectionTarget.produce( creationContext );
injectionTarget.inject( this.beanInstance, creationContext );
injectionTarget.postConstruct( this.beanInstance );
@ -84,15 +91,69 @@ public class ManagedBeanRegistryCdiDelayedImpl extends AbstractManagedBeanRegist
@Override
public void release() {
if ( !initialized ) {
log.debug( "Skipping release for delayed CDI bean [" + beanClass + "] as it was not initialized" );
log.debug( "Skipping release for (delayed) CDI bean [" + beanClass + "] as it was not initialized" );
return;
}
log.debug( "Releasing CDI listener : " + beanClass );
log.debug( "Releasing (delayed) CDI bean : " + beanClass );
injectionTarget.preDestroy( beanInstance );
injectionTarget.dispose( beanInstance );
creationalContext.release();
creationContext.release();
initialized = false;
}
}
private class NamedManagedBeanImpl<T> implements ManagedBean<T> {
private final String beanName;
private final Class<T> beanContract;
private boolean initialized = false;
private CreationalContext<T> creationContext;
private T beanInstance;
NamedManagedBeanImpl(String beanName, Class<T> beanContract) {
this.beanName = beanName;
this.beanContract = beanContract;
}
@Override
public Class<T> getBeanClass() {
return beanContract;
}
@Override
public T getBeanInstance() {
if ( !initialized ) {
initialize();
}
return beanInstance;
}
private void initialize() {
final Bean<T> bean = Helper.INSTANCE.getNamedBean( beanName, beanContract, beanManager );
this.creationContext = beanManager.createCreationalContext( bean );
this.beanInstance = beanContract.cast( beanManager.getReference( bean, beanContract, creationContext ) );
this.initialized = true;
}
@Override
public void release() {
if ( !initialized ) {
log.debugf( "Skipping release for (delayed) CDI bean [%s : %s] as it was not initialized", beanName, beanContract.getName() );
return;
}
log.debugf( "Releasing (delayed) CDI bean [%s : %s]", beanName, beanContract.getName() );
creationContext.release();
initialized = false;
}
}
}

View File

@ -8,6 +8,7 @@ package org.hibernate.resource.beans.internal;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.InjectionTarget;
@ -41,9 +42,14 @@ public class ManagedBeanRegistryCdiExtendedImpl
log.debugf( "Extended access requested to CDI BeanManager : " + beanManager );
}
@Override
protected <T> ManagedBean<T> createBean(Class<T> beanClass) {
return new ManagedBeanImpl<>( beanClass );
}
@Override
protected <T> ManagedBean<T> createBean(String beanName, Class<T> beanContract) {
return new ManagedBeanImpl<>( beanContract );
return new NamedManagedBeanImpl<>( beanName, beanContract );
}
@Override
@ -67,27 +73,13 @@ public class ManagedBeanRegistryCdiExtendedImpl
private boolean initialized = false;
private InjectionTarget<T> injectionTarget;
private CreationalContext<T> creationalContext;
private CreationalContext<T> creationContext;
private T beanInstance;
private ManagedBeanImpl(Class<T> beanClass) {
this.beanClass = beanClass;
}
public void initialize() {
final BeanManager beanManager = getUsableBeanManager();
AnnotatedType<T> annotatedType = beanManager.createAnnotatedType( beanClass );
this.injectionTarget = beanManager.createInjectionTarget( annotatedType );
this.creationalContext = beanManager.createCreationalContext( null );
this.beanInstance = injectionTarget.produce( creationalContext );
injectionTarget.inject( this.beanInstance, creationalContext );
injectionTarget.postConstruct( this.beanInstance );
this.initialized = true;
}
@Override
public Class<T> getBeanClass() {
return beanClass;
@ -101,16 +93,86 @@ public class ManagedBeanRegistryCdiExtendedImpl
return beanInstance;
}
private void initialize() {
final BeanManager beanManager = getUsableBeanManager();
AnnotatedType<T> annotatedType = beanManager.createAnnotatedType( beanClass );
this.injectionTarget = beanManager.createInjectionTarget( annotatedType );
this.creationContext = beanManager.createCreationalContext( null );
this.beanInstance = injectionTarget.produce( creationContext );
injectionTarget.inject( this.beanInstance, creationContext );
injectionTarget.postConstruct( this.beanInstance );
this.initialized = true;
}
public void release() {
if ( !initialized ) {
// log
log.debugf( "Skipping release for (extended) CDI bean [%s] as it was not initialized", beanClass.getName() );
return;
}
log.debugf( "Releasing (extended) CDI bean [%s]", beanClass.getName() );
injectionTarget.preDestroy( beanInstance );
injectionTarget.dispose( beanInstance );
creationalContext.release();
creationContext.release();
}
}
private class NamedManagedBeanImpl<T> implements ManagedBean<T> {
private final String beanName;
private final Class<T> beanContract;
private boolean initialized = false;
private CreationalContext<T> creationContext;
private T beanInstance;
public NamedManagedBeanImpl(
String beanName,
Class<T> beanContract) {
this.beanName = beanName;
this.beanContract = beanContract;
}
@Override
public Class<T> getBeanClass() {
return beanContract;
}
@Override
public T getBeanInstance() {
if ( !initialized ) {
initialize();
}
return beanInstance;
}
private void initialize() {
final BeanManager beanManager = getUsableBeanManager();
final Bean<T> bean = Helper.INSTANCE.getNamedBean( beanName, beanContract, beanManager );
this.creationContext = beanManager.createCreationalContext( bean );
this.beanInstance = beanContract.cast( beanManager.getReference( bean, beanContract, creationContext ) );
this.initialized = true;
}
@Override
public void release() {
if ( !initialized ) {
log.debugf( "Skipping release for (extended) CDI bean [%s : %s] as it was not initialized", beanName, beanContract.getName() );
return;
}
log.debugf( "Releasing (extended) CDI bean [%s : %s]", beanName, beanContract.getName() );
creationContext.release();
initialized = false;
}
}
}

View File

@ -8,6 +8,7 @@ package org.hibernate.resource.beans.internal;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.InjectionTarget;
@ -36,15 +37,23 @@ class ManagedBeanRegistryCdiStandardImpl extends AbstractManagedBeanRegistry {
log.debugf( "Standard access requested to CDI BeanManager : " + beanManager );
}
@Override
protected <T> ManagedBean<T> createBean(Class<T> beanClass) {
return new ManagedBeanImpl<>( beanClass );
}
@Override
protected <T> ManagedBean<T> createBean(String beanName, Class<T> beanContract) {
return new ManagedBeanImpl<>( beanContract );
return new NamedManagedBeanImpl<>( beanName, beanContract );
}
private class ManagedBeanImpl<T> implements ManagedBean<T> {
private final Class<T> beanClass;
private final InjectionTarget<T> injectionTarget;
private final CreationalContext<T> creationalContext;
private boolean initialized;
private final CreationalContext<T> creationContext;
private final T beanInstance;
public ManagedBeanImpl(Class<T> beanClass) {
@ -52,10 +61,10 @@ class ManagedBeanRegistryCdiStandardImpl extends AbstractManagedBeanRegistry {
AnnotatedType<T> annotatedType = beanManager.createAnnotatedType( beanClass );
this.injectionTarget = beanManager.createInjectionTarget( annotatedType );
this.creationalContext = beanManager.createCreationalContext( null );
this.creationContext = beanManager.createCreationalContext( null );
this.beanInstance = injectionTarget.produce( creationalContext );
injectionTarget.inject( this.beanInstance, creationalContext );
this.beanInstance = injectionTarget.produce( creationContext );
injectionTarget.inject( this.beanInstance, creationContext );
injectionTarget.postConstruct( this.beanInstance );
}
@ -72,9 +81,61 @@ class ManagedBeanRegistryCdiStandardImpl extends AbstractManagedBeanRegistry {
@Override
public void release() {
if ( !initialized ) {
log.debugf( "Skipping release for (standard) CDI bean [%s] as it was not initialized", beanClass.getName() );
return;
}
log.debugf( "Releasing (standard) CDI bean [%s]", beanClass.getName() );
injectionTarget.preDestroy( beanInstance );
injectionTarget.dispose( beanInstance );
creationalContext.release();
creationContext.release();
}
}
private class NamedManagedBeanImpl<T> implements ManagedBean<T> {
private final String beanName;
private final Class<T> beanContract;
private boolean initialized;
private CreationalContext<T> creationContext;
private T beanInstance;
private NamedManagedBeanImpl(String beanName, Class<T> beanContract) {
this.beanName = beanName;
this.beanContract = beanContract;
final Bean<T> bean = Helper.INSTANCE.getNamedBean( beanName, beanContract, beanManager );
this.creationContext = beanManager.createCreationalContext( bean );
this.beanInstance = beanContract.cast( beanManager.getReference( bean, beanContract, creationContext ) );
this.initialized = true;
}
@Override
public Class<T> getBeanClass() {
return beanContract;
}
@Override
public T getBeanInstance() {
return beanInstance;
}
@Override
public void release() {
if ( !initialized ) {
log.debugf( "Skipping release for (standard) CDI bean [%s : %s] as it was not initialized", beanName, beanContract.getName() );
return;
}
log.debugf( "Releasing (standard) CDI bean [%s : %s]", beanName, beanContract.getName() );
creationContext.release();
initialized = false;
}
}
}

View File

@ -23,12 +23,13 @@ public class ManagedBeanRegistryDirectImpl extends AbstractManagedBeanRegistry {
private static final Logger log = Logger.getLogger( ManagedBeanRegistryDirectImpl.class );
/**
* Singleton access
*/
public static final ManagedBeanRegistryDirectImpl INSTANCE = new ManagedBeanRegistryDirectImpl();
@SuppressWarnings("WeakerAccess")
public ManagedBeanRegistryDirectImpl() {
}
private ManagedBeanRegistryDirectImpl() {
@Override
protected <T> ManagedBean<T> createBean(Class<T> beanClass) {
return new ManagedBeanImpl<>( beanClass );
}
@Override

View File

@ -0,0 +1,28 @@
/*
* 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.resource.beans.internal;
import javax.inject.Named;
/**
* Used to locate named CDI beans.
*
* @author Yoann Rodière
* @author Steve Ebersole
*/
class NamedBeanQualifier extends javax.enterprise.util.AnnotationLiteral<Named> implements Named {
private final String name;
NamedBeanQualifier(String name) {
this.name = name;
}
@Override
public String value() {
return name;
}
}

View File

@ -22,9 +22,44 @@ public abstract class AbstractManagedBeanRegistry implements ManagedBeanRegistry
private Map<String,ManagedBean<?>> registrations = new HashMap<>();
@Override
@SuppressWarnings("unchecked")
public <T> ManagedBean<T> getBean(String beanName, Class<T> beanContract) {
final ManagedBean<T> existing = (ManagedBean<T>) registrations.get( beanName );
public <T> ManagedBean<T> getBean(Class<T> beanClass, boolean shouldRegistryManageLifecycle) {
if ( shouldRegistryManageLifecycle ) {
return getCacheableBean( beanClass );
}
else {
return createBean( beanClass );
}
}
@SuppressWarnings({"WeakerAccess", "unchecked"})
protected <T> ManagedBean<T> getCacheableBean(Class<T> beanClass) {
final String beanName = beanClass.getName();
final ManagedBean existing = registrations.get( beanName );
if ( existing != null ) {
return existing;
}
final ManagedBean<T> bean = createBean( beanClass );
registrations.put( beanName, bean );
return bean;
}
@SuppressWarnings("WeakerAccess")
protected abstract <T> ManagedBean<T> createBean(Class<T> beanClass);
@Override
public <T> ManagedBean<T> getBean(String beanName, Class<T> beanContract, boolean shouldRegistryManageLifecycle) {
if ( shouldRegistryManageLifecycle ) {
return getCacheableBean( beanName, beanContract );
}
else {
return createBean( beanName, beanContract );
}
}
@SuppressWarnings({"WeakerAccess", "unchecked"})
protected <T> ManagedBean<T> getCacheableBean(String beanName, Class<T> beanContract) {
final ManagedBean existing = registrations.get( beanName );
if ( existing != null ) {
return existing;
}
@ -44,7 +79,7 @@ public abstract class AbstractManagedBeanRegistry implements ManagedBeanRegistry
@Override
public void stop() {
BeansMessageLogger.CDI_LOGGER.stoppingManagedBeanRegistry( this );
BeansMessageLogger.BEANS_LOGGER.stoppingManagedBeanRegistry( this );
forEachBean( ManagedBean::release );
registrations.clear();
}

View File

@ -12,7 +12,18 @@ package org.hibernate.resource.beans.spi;
* @author Steve Ebersole
*/
public interface ManagedBean<T> {
/**
* The bean Java type
*/
Class<T> getBeanClass();
/**
* The bean reference
*/
T getBeanInstance();
/**
* Release any resources
*/
void release();
}

View File

@ -18,15 +18,32 @@ import org.hibernate.service.Service;
*/
public interface ManagedBeanRegistry extends Service {
/**
* Get a bean reference, by class. By default, calls
* {@link #getBean(String, Class)} using the beanClass's name
* Get a bean reference, by class.
*
* @apiNote `shouldRegistryManageLifecycle` has multiple implications that are
* important to understand. First it indicates whether the registry should
* handle releasing (end lifecycle) the bean or whether the caller will handle
* that. It also indicates whether cached references will be returned, or whether
* new references will be returned each time. `true` means that cached references
* can be returned and the registry will handle releasing when the registry is itself
* released (generally when the SessionFactory is closed). `false` means that
* new references should be returned for every call and the caller will handle
* the release calls itself.
*/
default <T> ManagedBean<T> getBean(Class<T> beanClass) {
return getBean( beanClass.getName(), beanClass );
}
<T> ManagedBean<T> getBean(Class<T> beanClass, boolean shouldRegistryManageLifecycle);
/**
* Get a bean reference by name, typed as the given bean contract.
* Get a bean reference by name and contract.
*
* @apiNote `shouldRegistryManageLifecycle` has multiple implications that are
* important to understand. First it indicates whether the registry should
* handle releasing (end lifecycle) the bean or whether the caller will handle
* that. It also indicates whether cached references will be returned, or whether
* new references will be returned each time. `true` means that cached references
* can be returned and the registry will handle releasing when the registry is itself
* released (generally when the SessionFactory is closed). `false` means that
* new references should be returned for every call and the caller will handle
* the release calls itself.
*/
<T> ManagedBean<T> getBean(String beanName, Class<T> contract);
<T> ManagedBean<T> getBean(String beanName, Class<T> beanContract, boolean shouldRegistryManageLifecycle);
}

View File

@ -43,8 +43,7 @@ public class ManagedBeanRegistryInitiator implements StandardServiceInitiator<Ma
final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
final ConfigurationService cfgSvc = serviceRegistry.getService( ConfigurationService.class );
final CompositeManagedBeanRegistry beanRegistry = new CompositeManagedBeanRegistry();
ManagedBeanRegistry primaryCdiBasedRegistry = null;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// apply CDI support
@ -53,15 +52,18 @@ public class ManagedBeanRegistryInitiator implements StandardServiceInitiator<Ma
final Object beanManagerRef = cfgSvc.getSettings().get( AvailableSettings.CDI_BEAN_MANAGER );
if ( beanManagerRef != null ) {
if ( !isCdiAvailable ) {
BeansMessageLogger.CDI_LOGGER.beanManagerButCdiNotAvailable( beanManagerRef );
BeansMessageLogger.BEANS_LOGGER.beanManagerButCdiNotAvailable( beanManagerRef );
}
beanRegistry.addDelegate(
ManagedBeanRegistryCdiBuilder.fromBeanManagerReference( beanManagerRef, serviceRegistry )
);
primaryCdiBasedRegistry = ManagedBeanRegistryCdiBuilder.fromBeanManagerReference( beanManagerRef, serviceRegistry );
}
else {
if ( isCdiAvailable ) {
BeansMessageLogger.BEANS_LOGGER.noBeanManagerButCdiAvailable();
}
}
return beanRegistry;
return new CompositeManagedBeanRegistry( primaryCdiBasedRegistry );
}
private static boolean isCdiAvailable(ClassLoaderService classLoaderService) {

View File

@ -14,7 +14,6 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import org.hibernate.boot.registry.BootstrapServiceRegistry;
import org.hibernate.cfg.Environment;

View File

@ -0,0 +1,42 @@
/*
* 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.service.spi;
import java.util.List;
/**
* Extension to Manageable for things that are optionally Manageable depending
* on some internal state. E.g. services that wrap other services wanting to
* delegate manageablity if the wrapped service is Manageable.
*
* @author Steve Ebersole
*/
public interface OptionallyManageable extends Manageable {
/**
* Any wrapped services that are Manageable. Never return `null`; an empty
* List should be returned instead.
*/
List<Manageable> getRealManageables();
@Override
default String getManagementDomain() {
// Generally the wrapper is not Manageable itself
return null;
}
@Override
default String getManagementServiceType() {
// Generally the wrapper is not Manageable itself
return null;
}
@Override
default Object getManagementBean() {
// Generally the wrapper is not Manageable itself
return null;
}
}