diff --git a/hibernate-core/src/main/java/org/hibernate/service/BootstrapServiceRegistryBuilder.java b/hibernate-core/src/main/java/org/hibernate/service/BootstrapServiceRegistryBuilder.java index bac6f9d977..44046e0cf2 100644 --- a/hibernate-core/src/main/java/org/hibernate/service/BootstrapServiceRegistryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/service/BootstrapServiceRegistryBuilder.java @@ -45,6 +45,7 @@ public class BootstrapServiceRegistryBuilder { private final LinkedHashSet providedIntegrators = new LinkedHashSet(); private List providedClassLoaders; private ClassLoaderService providedClassLoaderService; + private boolean autoCloseRegistry = true; /** * Add an {@link Integrator} to be applied to the bootstrap registry. @@ -141,6 +142,35 @@ public class BootstrapServiceRegistryBuilder { public BootstrapServiceRegistryBuilder withEnvironmentClassLoader(ClassLoader classLoader) { return with( classLoader ); } + + /** + * By default, when a ServiceRegistry is no longer referenced by any other + * registries as a parent it will be closed. + *

+ * Some applications that explicitly build "shared registries" may want to + * circumvent that behavior. + *

+ * This method indicates that the registry being built should not be + * automatically closed. The caller agrees to take responsibility to + * close it themselves. + * + * @return this, for method chaining + */ + public BootstrapServiceRegistryBuilder disableAutoClose() { + this.autoCloseRegistry = false; + return this; + } + + /** + * See the discussion on {@link #disableAutoClose}. This method enables + * the auto-closing. + * + * @return this, for method chaining + */ + public BootstrapServiceRegistryBuilder enableAutoClose() { + this.autoCloseRegistry = true; + return this; + } /** * Build the bootstrap registry. @@ -160,6 +190,6 @@ public class BootstrapServiceRegistryBuilder { classLoaderService ); - return new BootstrapServiceRegistryImpl( classLoaderService, integratorService ); + return new BootstrapServiceRegistryImpl( autoCloseRegistry, classLoaderService, integratorService ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/service/ServiceRegistryBuilder.java b/hibernate-core/src/main/java/org/hibernate/service/ServiceRegistryBuilder.java index df8cf184c4..b8e480e67a 100644 --- a/hibernate-core/src/main/java/org/hibernate/service/ServiceRegistryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/service/ServiceRegistryBuilder.java @@ -66,6 +66,8 @@ public class ServiceRegistryBuilder { private final Map settings; private final List initiators = standardInitiatorList(); private final List providedServices = new ArrayList(); + + private boolean autoCloseRegistry = true; private final BootstrapServiceRegistry bootstrapServiceRegistry; @@ -232,6 +234,34 @@ public class ServiceRegistryBuilder { providedServices.add( new ProvidedService( serviceRole, service ) ); return this; } + /** + * By default, when a ServiceRegistry is no longer referenced by any other + * registries as a parent it will be closed. + *

+ * Some applications that explicitly build "shared registries" may want to + * circumvent that behavior. + *

+ * This method indicates that the registry being built should not be + * automatically closed. The caller agrees to take responsibility to + * close it themselves. + * + * @return this, for method chaining + */ + public ServiceRegistryBuilder disableAutoClose() { + this.autoCloseRegistry = false; + return this; + } + + /** + * See the discussion on {@link #disableAutoClose}. This method enables + * the auto-closing. + * + * @return this, for method chaining + */ + public ServiceRegistryBuilder enableAutoClose() { + this.autoCloseRegistry = true; + return this; + } /** * Build the service registry accounting for all settings and service initiators and services. @@ -250,7 +280,7 @@ public class ServiceRegistryBuilder { } } - return new StandardServiceRegistryImpl( bootstrapServiceRegistry, initiators, providedServices, settingsCopy ); + return new StandardServiceRegistryImpl( autoCloseRegistry, bootstrapServiceRegistry, initiators, providedServices, settingsCopy ); } /** diff --git a/hibernate-core/src/main/java/org/hibernate/service/internal/AbstractServiceRegistryImpl.java b/hibernate-core/src/main/java/org/hibernate/service/internal/AbstractServiceRegistryImpl.java index a4ef7bb376..6c79d62a6e 100644 --- a/hibernate-core/src/main/java/org/hibernate/service/internal/AbstractServiceRegistryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/service/internal/AbstractServiceRegistryImpl.java @@ -67,6 +67,7 @@ public abstract class AbstractServiceRegistryImpl // assume 20 services for initial sizing private final List serviceBindingList = CollectionHelper.arrayList( 20 ); + private boolean autoCloseRegistry; private Set childRegistries; @SuppressWarnings( {"UnusedDeclaration"}) @@ -74,16 +75,35 @@ public abstract class AbstractServiceRegistryImpl this( (ServiceRegistryImplementor) null ); } + @SuppressWarnings( {"UnusedDeclaration"}) + protected AbstractServiceRegistryImpl(boolean autoCloseRegistry) { + this( (ServiceRegistryImplementor) null, autoCloseRegistry ); + } + protected AbstractServiceRegistryImpl(ServiceRegistryImplementor parent) { + this( parent, true ); + } + + protected AbstractServiceRegistryImpl( + ServiceRegistryImplementor parent, + boolean autoCloseRegistry) { this.parent = parent; + this.autoCloseRegistry = autoCloseRegistry; this.parent.registerChild( this ); } public AbstractServiceRegistryImpl(BootstrapServiceRegistry bootstrapServiceRegistry) { + this( bootstrapServiceRegistry, true ); + } + + public AbstractServiceRegistryImpl( + BootstrapServiceRegistry bootstrapServiceRegistry, + boolean autoCloseRegistry) { if ( ! ServiceRegistryImplementor.class.isInstance( bootstrapServiceRegistry ) ) { throw new IllegalArgumentException( "Boot-strap registry was not " ); } this.parent = (ServiceRegistryImplementor) bootstrapServiceRegistry; + this.autoCloseRegistry = autoCloseRegistry; this.parent.registerChild( this ); } @@ -332,11 +352,19 @@ public abstract class AbstractServiceRegistryImpl } childRegistries.remove( child ); if ( childRegistries.isEmpty() ) { - LOG.debug( - "Implicitly destroying ServiceRegistry on de-registration " + - "of all child ServiceRegistries" - ); - destroy(); + if ( autoCloseRegistry ) { + LOG.debug( + "Implicitly destroying ServiceRegistry on de-registration " + + "of all child ServiceRegistries" + ); + destroy(); + } + else { + LOG.debug( + "Skipping implicitly destroying ServiceRegistry on de-registration " + + "of all child ServiceRegistries" + ); + } } } } diff --git a/hibernate-core/src/main/java/org/hibernate/service/internal/BootstrapServiceRegistryImpl.java b/hibernate-core/src/main/java/org/hibernate/service/internal/BootstrapServiceRegistryImpl.java index 42b4e3e51f..8ba41ae6af 100644 --- a/hibernate-core/src/main/java/org/hibernate/service/internal/BootstrapServiceRegistryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/service/internal/BootstrapServiceRegistryImpl.java @@ -61,6 +61,7 @@ public class BootstrapServiceRegistryImpl private static final LinkedHashSet NO_INTEGRATORS = new LinkedHashSet(); + private final boolean autoCloseRegistry; private boolean active = true; private final ServiceBinding classLoaderServiceBinding; @@ -71,10 +72,19 @@ public class BootstrapServiceRegistryImpl public BootstrapServiceRegistryImpl() { this( new ClassLoaderServiceImpl(), NO_INTEGRATORS ); } - + public BootstrapServiceRegistryImpl( ClassLoaderService classLoaderService, IntegratorService integratorService) { + this( true, classLoaderService, integratorService ); + } + + public BootstrapServiceRegistryImpl( + boolean autoCloseRegistry, + ClassLoaderService classLoaderService, + IntegratorService integratorService) { + this.autoCloseRegistry = autoCloseRegistry; + this.classLoaderServiceBinding = new ServiceBinding( this, ClassLoaderService.class, @@ -92,7 +102,7 @@ public class BootstrapServiceRegistryImpl public BootstrapServiceRegistryImpl( ClassLoaderService classLoaderService, LinkedHashSet providedIntegrators) { - this( classLoaderService, new IntegratorServiceImpl( providedIntegrators, classLoaderService ) ); + this( true, classLoaderService, new IntegratorServiceImpl( providedIntegrators, classLoaderService ) ); } @@ -189,8 +199,13 @@ public class BootstrapServiceRegistryImpl } childRegistries.remove( child ); if ( childRegistries.isEmpty() ) { - LOG.debug( "Implicitly destroying Boot-strap registry on de-registration " + "of all child ServiceRegistries" ); - destroy(); + if ( autoCloseRegistry ) { + LOG.debug( "Implicitly destroying Boot-strap registry on de-registration " + "of all child ServiceRegistries" ); + destroy(); + } + else { + LOG.debug( "Skipping implicitly destroying Boot-strap registry on de-registration " + "of all child ServiceRegistries" ); + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/service/internal/StandardServiceRegistryImpl.java b/hibernate-core/src/main/java/org/hibernate/service/internal/StandardServiceRegistryImpl.java index 72f064ea80..4a7e2a4445 100644 --- a/hibernate-core/src/main/java/org/hibernate/service/internal/StandardServiceRegistryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/service/internal/StandardServiceRegistryImpl.java @@ -48,7 +48,17 @@ public class StandardServiceRegistryImpl extends AbstractServiceRegistryImpl imp List serviceInitiators, List providedServices, Map configurationValues) { - super( bootstrapServiceRegistry ); + this( true, bootstrapServiceRegistry, serviceInitiators, providedServices, configurationValues ); + } + + @SuppressWarnings( {"unchecked"}) + public StandardServiceRegistryImpl( + boolean autoCloseRegistry, + BootstrapServiceRegistry bootstrapServiceRegistry, + List serviceInitiators, + List providedServices, + Map configurationValues) { + super( bootstrapServiceRegistry, autoCloseRegistry ); this.configurationValues = configurationValues;