diff --git a/hibernate-core/src/main/java/org/hibernate/boot/registry/BootstrapServiceRegistryBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/registry/BootstrapServiceRegistryBuilder.java index ce59202409..f6c2a67f6e 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/registry/BootstrapServiceRegistryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/registry/BootstrapServiceRegistryBuilder.java @@ -51,10 +51,13 @@ import org.hibernate.integrator.spi.Integrator; */ public class BootstrapServiceRegistryBuilder { private final LinkedHashSet providedIntegrators = new LinkedHashSet(); + private List providedClassLoaders; private ClassLoaderService providedClassLoaderService; private StrategySelectorBuilder strategySelectorBuilder = new StrategySelectorBuilder(); - + + private boolean autoCloseRegistry = true; + /** * Add an {@link Integrator} to be applied to the bootstrap registry. * @@ -190,6 +193,35 @@ public class BootstrapServiceRegistryBuilder { 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 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. * @@ -219,6 +251,7 @@ public class BootstrapServiceRegistryBuilder { return new BootstrapServiceRegistryImpl( + autoCloseRegistry, classLoaderService, strategySelectorBuilder.buildSelector( classLoaderService ), integratorService diff --git a/hibernate-core/src/main/java/org/hibernate/boot/registry/StandardServiceRegistryBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/registry/StandardServiceRegistryBuilder.java index 949be8967b..1223af06b9 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/registry/StandardServiceRegistryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/registry/StandardServiceRegistryBuilder.java @@ -61,6 +61,8 @@ public class StandardServiceRegistryBuilder { private final List initiators = standardInitiatorList(); private final List providedServices = new ArrayList(); + private boolean autoCloseRegistry = true; + private final BootstrapServiceRegistry bootstrapServiceRegistry; private final ConfigLoader configLoader; @@ -202,6 +204,35 @@ public class StandardServiceRegistryBuilder { 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 StandardServiceRegistryBuilder disableAutoClose() { + this.autoCloseRegistry = false; + return this; + } + + /** + * See the discussion on {@link #disableAutoClose}. This method enables + * the auto-closing. + * + * @return this, for method chaining + */ + public StandardServiceRegistryBuilder enableAutoClose() { + this.autoCloseRegistry = true; + return this; + } + /** * Build the StandardServiceRegistry. * @@ -217,7 +248,13 @@ public class StandardServiceRegistryBuilder { applyServiceContributingIntegrators(); applyServiceContributors(); - return new StandardServiceRegistryImpl( bootstrapServiceRegistry, initiators, providedServices, settingsCopy ); + return new StandardServiceRegistryImpl( + autoCloseRegistry, + bootstrapServiceRegistry, + initiators, + providedServices, + settingsCopy + ); } @SuppressWarnings("deprecation") diff --git a/hibernate-core/src/main/java/org/hibernate/boot/registry/internal/BootstrapServiceRegistryImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/registry/internal/BootstrapServiceRegistryImpl.java index d0515a7937..539048174c 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/registry/internal/BootstrapServiceRegistryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/registry/internal/BootstrapServiceRegistryImpl.java @@ -45,8 +45,6 @@ import org.hibernate.service.spi.ServiceInitiator; import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.service.spi.Stoppable; -import org.jboss.logging.Logger; - /** * {@link ServiceRegistry} implementation containing specialized "bootstrap" services, specifically:

    *
  • {@link ClassLoaderService}
  • @@ -66,6 +64,7 @@ public class BootstrapServiceRegistryImpl private static final CoreMessageLogger LOG = CoreLogging.messageLogger( BootstrapServiceRegistryImpl.class ); + private final boolean autoCloseRegistry; private boolean active = true; private static final LinkedHashSet NO_INTEGRATORS = new LinkedHashSet(); @@ -87,7 +86,6 @@ public class BootstrapServiceRegistryImpl public BootstrapServiceRegistryImpl() { this( new ClassLoaderServiceImpl(), NO_INTEGRATORS ); } - /** * Constructs a BootstrapServiceRegistryImpl. * @@ -102,6 +100,28 @@ public class BootstrapServiceRegistryImpl public BootstrapServiceRegistryImpl( ClassLoaderService classLoaderService, LinkedHashSet providedIntegrators) { + this( true, classLoaderService, providedIntegrators ); + } + + /** + * Constructs a BootstrapServiceRegistryImpl. + * + * Do not use directly generally speaking. Use {@link org.hibernate.boot.registry.BootstrapServiceRegistryBuilder} + * instead. + * + * @param autoCloseRegistry See discussion on + * {@link org.hibernate.boot.registry.BootstrapServiceRegistryBuilder#disableAutoClose} + * @param classLoaderService The ClassLoaderService to use + * @param providedIntegrators The group of explicitly provided integrators + * + * @see org.hibernate.boot.registry.BootstrapServiceRegistryBuilder + */ + public BootstrapServiceRegistryImpl( + boolean autoCloseRegistry, + ClassLoaderService classLoaderService, + LinkedHashSet providedIntegrators) { + this.autoCloseRegistry = autoCloseRegistry; + this.classLoaderServiceBinding = new ServiceBinding( this, ClassLoaderService.class, @@ -139,6 +159,31 @@ public class BootstrapServiceRegistryImpl ClassLoaderService classLoaderService, StrategySelector strategySelector, IntegratorService integratorService) { + this( true, classLoaderService, strategySelector, integratorService ); + } + + + /** + * Constructs a BootstrapServiceRegistryImpl. + * + * Do not use directly generally speaking. Use {@link org.hibernate.boot.registry.BootstrapServiceRegistryBuilder} + * instead. + * + * @param autoCloseRegistry See discussion on + * {@link org.hibernate.boot.registry.BootstrapServiceRegistryBuilder#disableAutoClose} + * @param classLoaderService The ClassLoaderService to use + * @param strategySelector The StrategySelector to use + * @param integratorService The IntegratorService to use + * + * @see org.hibernate.boot.registry.BootstrapServiceRegistryBuilder + */ + public BootstrapServiceRegistryImpl( + boolean autoCloseRegistry, + ClassLoaderService classLoaderService, + StrategySelector strategySelector, + IntegratorService integratorService) { + this.autoCloseRegistry = autoCloseRegistry; + this.classLoaderServiceBinding = new ServiceBinding( this, ClassLoaderService.class, @@ -259,11 +304,19 @@ 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/boot/registry/internal/StandardServiceRegistryImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/registry/internal/StandardServiceRegistryImpl.java index 137d35b2ee..607fc4820e 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/registry/internal/StandardServiceRegistryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/registry/internal/StandardServiceRegistryImpl.java @@ -61,7 +61,30 @@ public class StandardServiceRegistryImpl extends AbstractServiceRegistryImpl imp List serviceInitiators, List providedServices, Map configurationValues) { - super( bootstrapServiceRegistry ); + this( true, bootstrapServiceRegistry, serviceInitiators, providedServices, configurationValues ); + } + + /** + * Constructs a StandardServiceRegistryImpl. Should not be instantiated directly; use + * {@link org.hibernate.boot.registry.StandardServiceRegistryBuilder} instead + * + * @param autoCloseRegistry See discussion on + * {@link org.hibernate.boot.registry.StandardServiceRegistryBuilder#disableAutoClose} + * @param bootstrapServiceRegistry The bootstrap service registry. + * @param serviceInitiators Any StandardServiceInitiators provided by the user to the builder + * @param providedServices Any standard services provided directly to the builder + * @param configurationValues Configuration values + * + * @see org.hibernate.boot.registry.StandardServiceRegistryBuilder + */ + @SuppressWarnings( {"unchecked"}) + public StandardServiceRegistryImpl( + boolean autoCloseRegistry, + BootstrapServiceRegistry bootstrapServiceRegistry, + List serviceInitiators, + List providedServices, + Map configurationValues) { + super( bootstrapServiceRegistry, autoCloseRegistry ); this.configurationValues = configurationValues; 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 ca7716d8b0..23af9653ab 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 @@ -72,6 +72,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"}) @@ -79,20 +80,39 @@ 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.allowCrawling = ConfigurationHelper.getBoolean( ALLOW_CRAWLING, Environment.getProperties(), true ); + 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( "ServiceRegistry parent needs to implement ServiceRegistryImplementor" ); } this.parent = (ServiceRegistryImplementor) bootstrapServiceRegistry; this.allowCrawling = ConfigurationHelper.getBoolean( ALLOW_CRAWLING, Environment.getProperties(), true ); + this.autoCloseRegistry = autoCloseRegistry; this.parent.registerChild( this ); } @@ -382,11 +402,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/test/java/org/hibernate/connection/ConnectionCreatorTest.java b/hibernate-core/src/test/java/org/hibernate/connection/ConnectionCreatorTest.java index 26b86905a3..4b12f148d6 100644 --- a/hibernate-core/src/test/java/org/hibernate/connection/ConnectionCreatorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/connection/ConnectionCreatorTest.java @@ -38,10 +38,9 @@ import org.hibernate.exception.JDBCConnectionException; import org.hibernate.service.Service; import org.hibernate.service.internal.ProvidedService; -import org.junit.Test; - import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.junit.Test; import static org.junit.Assert.fail; @@ -55,6 +54,7 @@ public class ConnectionCreatorTest extends BaseUnitTestCase { DriverConnectionCreator connectionCreator = new DriverConnectionCreator( (Driver) Class.forName( "org.h2.Driver" ).newInstance(), new StandardServiceRegistryImpl( + true, new BootstrapServiceRegistryImpl(), Collections.emptyList(), Collections.emptyList(),