diff --git a/documentation/src/main/asciidoc/introduction/Configuration.adoc b/documentation/src/main/asciidoc/introduction/Configuration.adoc index 5056c7c6d204..ddac4a3dc61c 100644 --- a/documentation/src/main/asciidoc/introduction/Configuration.adoc +++ b/documentation/src/main/asciidoc/introduction/Configuration.adoc @@ -355,9 +355,11 @@ You can set the size of Hibernate's built-in connection pool using this property |=== | Configuration property name | Purpose -| `hibernate.connection.pool_size` | The size of the built-in connection pool +| `hibernate.connection.pool_size` | The size of the connection pool |=== +This configuration property is also respected when you use Agroal, HikariCP, or c3p0 for connection pooling. + [CAUTION] // .The default connection pool is not meant for production use ==== diff --git a/documentation/src/main/asciidoc/introduction/Tuning.adoc b/documentation/src/main/asciidoc/introduction/Tuning.adoc index 13e44cd5d974..8c6d3a3f2ebb 100644 --- a/documentation/src/main/asciidoc/introduction/Tuning.adoc +++ b/documentation/src/main/asciidoc/introduction/Tuning.adoc @@ -72,6 +72,7 @@ The following settings are common to all connection pools supported by Hibernate .Common settings for connection pools [%breakable,cols="37,~"] |=== +| link:{doc-javadoc-url}/org/hibernate/cfg/JdbcSettings.html#POOL_SIZE[`hibernate.connection.pool_size`] | The size of the connection pool | link:{doc-javadoc-url}/org/hibernate/cfg/JdbcSettings.html#AUTOCOMMIT[`hibernate.connection.autocommit`] | The default autocommit mode | link:{doc-javadoc-url}/org/hibernate/cfg/JdbcSettings.html#ISOLATION[`hibernate.connection.isolation`] | The default transaction isolation level |=== diff --git a/hibernate-agroal/src/main/java/org/hibernate/agroal/internal/AgroalConnectionProvider.java b/hibernate-agroal/src/main/java/org/hibernate/agroal/internal/AgroalConnectionProvider.java index 092eaa8d7758..40fdf741d2ce 100644 --- a/hibernate-agroal/src/main/java/org/hibernate/agroal/internal/AgroalConnectionProvider.java +++ b/hibernate-agroal/src/main/java/org/hibernate/agroal/internal/AgroalConnectionProvider.java @@ -4,21 +4,24 @@ */ package org.hibernate.agroal.internal; +import java.io.Serial; import java.sql.Connection; import java.sql.SQLException; -import java.sql.DatabaseMetaData; import javax.sql.DataSource; import java.util.Map; import java.util.function.Consumer; import java.util.function.Function; +import io.agroal.api.configuration.AgroalConnectionFactoryConfiguration.TransactionIsolation; import org.hibernate.HibernateException; import org.hibernate.cfg.AgroalSettings; import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.JdbcSettings; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator; import org.hibernate.engine.jdbc.connections.internal.DatabaseConnectionInfoImpl; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; +import org.hibernate.engine.jdbc.connections.spi.ConnectionProviderConfigurationException; import org.hibernate.engine.jdbc.connections.spi.DatabaseConnectionInfo; import org.hibernate.internal.log.ConnectionInfoLogger; import org.hibernate.service.UnknownUnwrapTypeException; @@ -33,14 +36,19 @@ import io.agroal.api.security.NamePrincipal; import io.agroal.api.security.SimplePassword; +import static java.util.function.Function.identity; +import static java.util.stream.Collectors.toMap; import static org.hibernate.cfg.AgroalSettings.AGROAL_CONFIG_PREFIX; import static org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.allowJdbcMetadataAccess; /** - * ConnectionProvider based on Agroal connection pool - * To use this ConnectionProvider set:
 hibernate.connection.provider_class AgroalConnectionProvider 
- * - * Usual hibernate properties are supported: + * {@link ConnectionProvider} based on Agroal connection pool. + *

+ * To force the use of this {@code ConnectionProvider} set + * {@value org.hibernate.cfg.JdbcSettings#CONNECTION_PROVIDER} + * to {@code agroal}. + *

+ * Usual hibernate connection properties are supported: *

  *     hibernate.connection.driver_class
  *     hibernate.connection.url
@@ -49,8 +57,8 @@
  *     hibernate.connection.autocommit
  *     hibernate.connection.isolation
  * 
- * - * Other configuration options are available, using the {@code hibernate.agroal} prefix + *

+ * Other configuration options are available, using the {@code hibernate.agroal} prefix. * * @see AgroalSettings * @see AgroalPropertiesReader @@ -61,6 +69,8 @@ public class AgroalConnectionProvider implements ConnectionProvider, Configurable, Stoppable { public static final String CONFIG_PREFIX = AGROAL_CONFIG_PREFIX + "."; + + @Serial private static final long serialVersionUID = 1L; private AgroalDataSource agroalDataSource = null; private boolean isMetadataAccessAllowed = true; @@ -68,43 +78,52 @@ public class AgroalConnectionProvider implements ConnectionProvider, Configurabl // --- Configurable private static String extractIsolationAsString(Map properties) { - Integer isolation = ConnectionProviderInitiator.extractIsolation( properties ); - if ( isolation != null ) { - // Agroal resolves transaction isolation from the 'nice' name - return ConnectionProviderInitiator.toIsolationNiceName( isolation ); - } - return null; + final Integer isolation = ConnectionProviderInitiator.extractIsolation( properties ); + return isolation != null ? + // Agroal resolves transaction isolation from the 'nice' name + ConnectionProviderInitiator.toIsolationNiceName( isolation ) + : null; } private static void resolveIsolationSetting(Map properties, AgroalConnectionFactoryConfigurationSupplier cf) { - String isolationString = extractIsolationAsString( properties ); + final String isolationString = extractIsolationAsString( properties ); if ( isolationString != null ) { - cf.jdbcTransactionIsolation( AgroalConnectionFactoryConfiguration.TransactionIsolation.valueOf( isolationString ) ); + cf.jdbcTransactionIsolation( TransactionIsolation.valueOf( isolationString ) ); } } private static void copyProperty(Map properties, String key, Consumer consumer, Function converter) { - Object value = properties.get( key ); - if ( value instanceof String ) { - consumer.accept( converter.apply( (String) value ) ); + final Object value = properties.get( key ); + if ( value != null ) { + consumer.accept( converter.apply( value.toString() ) ); } } @Override - public void configure(Map props) throws HibernateException { - isMetadataAccessAllowed = allowJdbcMetadataAccess( props ); + public void configure(Map properties) throws HibernateException { + isMetadataAccessAllowed = allowJdbcMetadataAccess( properties ); ConnectionInfoLogger.INSTANCE.configureConnectionPool( "Agroal" ); try { - AgroalPropertiesReader agroalProperties = new AgroalPropertiesReader( CONFIG_PREFIX ) - .readProperties( (Map) props ); //TODO: this is a garbage cast - agroalProperties.modify().connectionPoolConfiguration( cp -> cp.connectionFactoryConfiguration( cf -> { - copyProperty( props, AvailableSettings.DRIVER, cf::connectionProviderClassName, Function.identity() ); - copyProperty( props, AvailableSettings.URL, cf::jdbcUrl, Function.identity() ); - copyProperty( props, AvailableSettings.USER, cf::principal, NamePrincipal::new ); - copyProperty( props, AvailableSettings.PASS, cf::credential, SimplePassword::new ); - copyProperty( props, AvailableSettings.AUTOCOMMIT, cf::autoCommit, Boolean::valueOf ); - resolveIsolationSetting( props, cf ); + final Map config = toStringValuedProperties( properties ); + if ( !properties.containsKey( AgroalSettings.AGROAL_MAX_SIZE ) ) { + final String maxSize = + properties.containsKey( JdbcSettings.POOL_SIZE ) + ? properties.get( JdbcSettings.POOL_SIZE ).toString() + : String.valueOf( 10 ); + config.put( AgroalSettings.AGROAL_MAX_SIZE, maxSize ); + } + final AgroalPropertiesReader agroalProperties = + new AgroalPropertiesReader( CONFIG_PREFIX ) + .readProperties( config ); + agroalProperties.modify() + .connectionPoolConfiguration( cp -> cp.connectionFactoryConfiguration( cf -> { + copyProperty( properties, JdbcSettings.DRIVER, cf::connectionProviderClassName, identity() ); + copyProperty( properties, JdbcSettings.URL, cf::jdbcUrl, identity() ); + copyProperty( properties, JdbcSettings.USER, cf::principal, NamePrincipal::new ); + copyProperty( properties, JdbcSettings.PASS, cf::credential, SimplePassword::new ); + copyProperty( properties, JdbcSettings.AUTOCOMMIT, cf::autoCommit, Boolean::valueOf ); + resolveIsolationSetting( properties, cf ); return cf; } ) ); @@ -112,10 +131,16 @@ public void configure(Map props) throws HibernateException { } catch ( Exception e ) { ConnectionInfoLogger.INSTANCE.unableToInstantiateConnectionPool( e ); - throw new HibernateException( e ); + throw new ConnectionProviderConfigurationException( + "Could not configure Agroal: " + e.getMessage(), e ); } } + private static Map toStringValuedProperties(Map properties) { + return properties.entrySet().stream() + .collect( toMap( Map.Entry::getKey, e -> e.getValue().toString() ) ); + } + // --- ConnectionProvider @Override @@ -138,30 +163,31 @@ public boolean supportsAggressiveRelease() { @Override public DatabaseConnectionInfo getDatabaseConnectionInfo(Dialect dialect) { - final AgroalConnectionPoolConfiguration acpc = agroalDataSource.getConfiguration().connectionPoolConfiguration(); + final AgroalConnectionPoolConfiguration acpc = + agroalDataSource.getConfiguration().connectionPoolConfiguration(); final AgroalConnectionFactoryConfiguration acfc = acpc.connectionFactoryConfiguration(); - - return new DatabaseConnectionInfoImpl( acfc.jdbcUrl(), - // Attempt to resolve the driver name from the dialect, in case it wasn't explicitly set and access to - // the database metadata is allowed - acfc.connectionProviderClass() != null ? acfc.connectionProviderClass().toString() : extractDriverNameFromMetadata(), + // Attempt to resolve the driver name from the dialect, + // in case it wasn't explicitly set and access to the + // database metadata is allowed + acfc.connectionProviderClass() != null + ? acfc.connectionProviderClass().toString() + : extractDriverNameFromMetadata(), dialect.getVersion(), Boolean.toString( acfc.autoCommit() ), acfc.jdbcTransactionIsolation() != null ? ConnectionProviderInitiator.toIsolationNiceName( acfc.jdbcTransactionIsolation().level() ) : null, acpc.minSize(), - acpc.minSize() + acpc.maxSize() ); } private String extractDriverNameFromMetadata() { if (isMetadataAccessAllowed) { try ( Connection conn = getConnection() ) { - DatabaseMetaData dbmd = conn.getMetaData(); - return dbmd.getDriverName(); + return conn.getMetaData().getDriverName(); } catch (SQLException e) { // Do nothing @@ -195,8 +221,11 @@ public T unwrap(Class unwrapType) { @Override public void stop() { if ( agroalDataSource != null ) { - ConnectionInfoLogger.INSTANCE.cleaningUpConnectionPool( agroalDataSource.getConfiguration().connectionPoolConfiguration(). - connectionFactoryConfiguration().jdbcUrl() ); + ConnectionInfoLogger.INSTANCE.cleaningUpConnectionPool( + agroalDataSource.getConfiguration() + .connectionPoolConfiguration() + .connectionFactoryConfiguration() + .jdbcUrl() ); agroalDataSource.close(); } } diff --git a/hibernate-agroal/src/main/java/org/hibernate/agroal/internal/package-info.java b/hibernate-agroal/src/main/java/org/hibernate/agroal/internal/package-info.java index 8ac3c9e6943a..dcd7eb663070 100644 --- a/hibernate-agroal/src/main/java/org/hibernate/agroal/internal/package-info.java +++ b/hibernate-agroal/src/main/java/org/hibernate/agroal/internal/package-info.java @@ -6,6 +6,6 @@ */ /** - * Implementation of ConnectionProvider using Agroal. + * Implementation of {@code ConnectionProvider} using Agroal. */ package org.hibernate.agroal.internal; diff --git a/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/C3P0ConnectionProvider.java b/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/C3P0ConnectionProvider.java index 27408fa059f2..a47a80ad4a9f 100644 --- a/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/C3P0ConnectionProvider.java +++ b/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/C3P0ConnectionProvider.java @@ -4,49 +4,66 @@ */ package org.hibernate.c3p0.internal; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; -import java.util.function.Function; -import javax.sql.DataSource; - import com.mchange.v2.c3p0.DataSources; - -import org.hibernate.HibernateException; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; -import org.hibernate.cfg.C3p0Settings; import org.hibernate.cfg.JdbcSettings; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator; import org.hibernate.engine.jdbc.connections.internal.DatabaseConnectionInfoImpl; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; +import org.hibernate.engine.jdbc.connections.spi.ConnectionProviderConfigurationException; import org.hibernate.engine.jdbc.connections.spi.DatabaseConnectionInfo; import org.hibernate.internal.log.ConnectionInfoLogger; -import org.hibernate.internal.util.PropertiesHelper; import org.hibernate.service.UnknownUnwrapTypeException; import org.hibernate.service.spi.Configurable; import org.hibernate.service.spi.ServiceRegistryAwareService; import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.service.spi.Stoppable; +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.function.Function; + +import static com.mchange.v2.c3p0.DataSources.pooledDataSource; +import static com.mchange.v2.c3p0.DataSources.unpooledDataSource; +import static java.util.Objects.requireNonNullElse; import static org.hibernate.c3p0.internal.C3P0MessageLogger.C3P0_MSG_LOGGER; +import static org.hibernate.cfg.C3p0Settings.C3P0_ACQUIRE_INCREMENT; +import static org.hibernate.cfg.C3p0Settings.C3P0_CONFIG_PREFIX; +import static org.hibernate.cfg.C3p0Settings.C3P0_IDLE_TEST_PERIOD; +import static org.hibernate.cfg.C3p0Settings.C3P0_MAX_SIZE; +import static org.hibernate.cfg.C3p0Settings.C3P0_MAX_STATEMENTS; +import static org.hibernate.cfg.C3p0Settings.C3P0_MIN_SIZE; +import static org.hibernate.cfg.C3p0Settings.C3P0_TIMEOUT; import static org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator.extractSetting; import static org.hibernate.internal.util.config.ConfigurationHelper.getBoolean; import static org.hibernate.internal.util.config.ConfigurationHelper.getInteger; /** - * A connection provider that uses a C3P0 connection pool. Hibernate will use this by - * default if the {@code hibernate.c3p0.*} properties are set. + * {@link ConnectionProvider} based on c3p0 connection pool. + *

+ * To force the use of this {@code ConnectionProvider} set + * {@value org.hibernate.cfg.JdbcSettings#CONNECTION_PROVIDER} + * to {@code c3p0}. + *

+ * Hibernate selects this by default if the {@code hibernate.c3p0.*} properties are set. * * @author various people * @see ConnectionProvider */ public class C3P0ConnectionProvider implements ConnectionProvider, Configurable, Stoppable, ServiceRegistryAwareService { - private static volatile String HIBERNATE_STYLE_SETTING_PREFIX = C3p0Settings.C3P0_CONFIG_PREFIX + "."; + + // as specified by c3p0 documentation: + public static final int DEFAULT_MIN_POOL_SIZE = 3; + public static final int DEFAULT_MAX_POOL_SIZE = 15; + + private static final String HIBERNATE_STYLE_SETTING_PREFIX = C3P0_CONFIG_PREFIX + "."; //swaldman 2006-08-28: define c3p0-style configuration parameters for properties with // hibernate-specific overrides to detect and warn about conflicting @@ -62,7 +79,7 @@ public class C3P0ConnectionProvider // hibernate sensibly lets default to minPoolSize, but we'll let users // override it with the c3p0-style property if they want. private static final String C3P0_STYLE_INITIAL_POOL_SIZE = "c3p0.initialPoolSize"; - private DataSource ds; + private DataSource dataSource; private Integer isolation; private boolean autocommit; @@ -71,7 +88,7 @@ public class C3P0ConnectionProvider @Override public Connection getConnection() throws SQLException { - final Connection connection = ds.getConnection(); + final Connection connection = dataSource.getConnection(); if ( isolation != null && isolation != connection.getTransactionIsolation() ) { connection.setTransactionIsolation( isolation ); } @@ -101,7 +118,7 @@ public T unwrap(Class unwrapType) { return (T) this; } else if ( DataSource.class.isAssignableFrom( unwrapType ) ) { - return (T) ds; + return (T) dataSource; } else { throw new UnknownUnwrapTypeException( unwrapType ); @@ -109,26 +126,56 @@ else if ( DataSource.class.isAssignableFrom( unwrapType ) ) { } @Override - public void configure(Map props) { - ConnectionInfoLogger.INSTANCE.configureConnectionPool( "C3p0" ); + public void configure(Map properties) { + ConnectionInfoLogger.INSTANCE.configureConnectionPool( "c3p0" ); final String jdbcDriverClass = extractSetting( - props, + properties, JdbcSettings.JAKARTA_JDBC_DRIVER, JdbcSettings.DRIVER, JdbcSettings.JPA_JDBC_DRIVER ); final String jdbcUrl = extractSetting( - props, + properties, JdbcSettings.JAKARTA_JDBC_URL, JdbcSettings.URL, JdbcSettings.JPA_JDBC_URL ); - final Properties connectionProps = ConnectionProviderInitiator.getConnectionProperties( props ); + loadDriverClass( jdbcDriverClass ); + + autocommit = getBoolean( JdbcSettings.AUTOCOMMIT, properties ); // defaults to false + isolation = ConnectionProviderInitiator.extractIsolation( properties ); + + final Properties connectionProps = ConnectionProviderInitiator.getConnectionProperties( properties ); + final Map poolSettings = poolSettings( properties ); + dataSource = createDataSource( jdbcUrl, connectionProps, poolSettings ); + + dbInfoProducer = dialect -> new DatabaseConnectionInfoImpl( + jdbcUrl, + jdbcDriverClass, + dialect.getVersion(), + Boolean.toString( autocommit ), + isolation != null ? ConnectionProviderInitiator.toIsolationNiceName( isolation ) : null, + requireNonNullElse( getInteger( C3P0_STYLE_MIN_POOL_SIZE.substring( 5 ), poolSettings ), + DEFAULT_MIN_POOL_SIZE ), + requireNonNullElse( getInteger( C3P0_STYLE_MAX_POOL_SIZE.substring( 5 ), poolSettings ), + DEFAULT_MAX_POOL_SIZE ) + ); + } - autocommit = getBoolean( JdbcSettings.AUTOCOMMIT, props ); + private DataSource createDataSource(String jdbcUrl, Properties connectionProps, Map poolProperties) { + try { + return pooledDataSource( unpooledDataSource( jdbcUrl, connectionProps ), poolProperties ); + } + catch (Exception e) { + ConnectionInfoLogger.INSTANCE.unableToInstantiateConnectionPool( e ); + throw new ConnectionProviderConfigurationException( + "Could not configure c3p0: " + e.getMessage(), e ); + } + } + private void loadDriverClass(String jdbcDriverClass) { if ( jdbcDriverClass == null ) { ConnectionInfoLogger.INSTANCE.jdbcDriverNotSpecified(); } @@ -140,79 +187,59 @@ public void configure(Map props) { throw new ClassLoadingException( "JDBC Driver class " + jdbcDriverClass + " not found", e ); } } + } - Integer minPoolSize = null; - Integer maxPoolSize = null; - try { - - //swaldman 2004-02-07: modify to allow null values to signify fall through to c3p0 PoolConfig defaults - minPoolSize = getInteger( C3p0Settings.C3P0_MIN_SIZE, props ); - maxPoolSize = getInteger( C3p0Settings.C3P0_MAX_SIZE, props ); - final Integer maxIdleTime = getInteger( C3p0Settings.C3P0_TIMEOUT, props ); - final Integer maxStatements = getInteger( C3p0Settings.C3P0_MAX_STATEMENTS, props ); - final Integer acquireIncrement = getInteger( C3p0Settings.C3P0_ACQUIRE_INCREMENT, props ); - final Integer idleTestPeriod = getInteger( C3p0Settings.C3P0_IDLE_TEST_PERIOD, props ); - - final Properties c3props = new Properties(); - - // turn hibernate.c3p0.* into c3p0.*, so c3p0 - // gets a chance to see all hibernate.c3p0.* - for ( String key : props.keySet() ) { - if ( key.startsWith( HIBERNATE_STYLE_SETTING_PREFIX ) ) { - final String newKey = key.substring( HIBERNATE_STYLE_SETTING_PREFIX.length() ); - if ( props.containsKey( newKey ) ) { - warnPropertyConflict( key, newKey ); - } - c3props.put( newKey, props.get( key ) ); + private Map poolSettings(Map hibernateProperties) { + //swaldman 2004-02-07: modify to allow null values to signify fall through to c3p0 PoolConfig defaults + Integer maxPoolSize = getInteger( C3P0_MAX_SIZE, hibernateProperties ); + if ( maxPoolSize == null ) { + // if hibernate.c3p0.max_size is not specified, use hibernate.connection.pool_size + maxPoolSize = getInteger( JdbcSettings.POOL_SIZE, hibernateProperties ); + } + final Integer minPoolSize = getInteger( C3P0_MIN_SIZE, hibernateProperties ); + final Integer maxIdleTime = getInteger( C3P0_TIMEOUT, hibernateProperties ); + final Integer maxStatements = getInteger( C3P0_MAX_STATEMENTS, hibernateProperties ); + final Integer acquireIncrement = getInteger( C3P0_ACQUIRE_INCREMENT, hibernateProperties ); + final Integer idleTestPeriod = getInteger( C3P0_IDLE_TEST_PERIOD, hibernateProperties ); + + final Map c3p0Properties = new HashMap<>(); + // turn hibernate.c3p0.* into c3p0.*, so c3p0 + // gets a chance to see all hibernate.c3p0.* + for ( String key : hibernateProperties.keySet() ) { + if ( key.startsWith( HIBERNATE_STYLE_SETTING_PREFIX ) ) { + final String newKey = key.substring( HIBERNATE_STYLE_SETTING_PREFIX.length() ); + if ( hibernateProperties.containsKey( newKey ) ) { + warnPropertyConflict( key, newKey ); } + c3p0Properties.put( newKey, hibernateProperties.get( key ) ); } - - setOverwriteProperty( C3p0Settings.C3P0_MIN_SIZE, C3P0_STYLE_MIN_POOL_SIZE, props, c3props, minPoolSize ); - setOverwriteProperty( C3p0Settings.C3P0_MAX_SIZE, C3P0_STYLE_MAX_POOL_SIZE, props, c3props, maxPoolSize ); - setOverwriteProperty( C3p0Settings.C3P0_TIMEOUT, C3P0_STYLE_MAX_IDLE_TIME, props, c3props, maxIdleTime ); - setOverwriteProperty( C3p0Settings.C3P0_MAX_STATEMENTS, C3P0_STYLE_MAX_STATEMENTS, props, c3props, maxStatements ); - setOverwriteProperty( C3p0Settings.C3P0_ACQUIRE_INCREMENT, C3P0_STYLE_ACQUIRE_INCREMENT, props, c3props, acquireIncrement ); - setOverwriteProperty( - C3p0Settings.C3P0_IDLE_TEST_PERIOD, - C3P0_STYLE_IDLE_CONNECTION_TEST_PERIOD, - props, - c3props, - idleTestPeriod - ); - - // revert to traditional hibernate behavior of setting initialPoolSize to minPoolSize - // unless otherwise specified with a c3p0.*-style parameter. - final Integer initialPoolSize = getInteger( C3P0_STYLE_INITIAL_POOL_SIZE, props ); - if ( initialPoolSize == null ) { - setOverwriteProperty( "", C3P0_STYLE_INITIAL_POOL_SIZE, props, c3props, minPoolSize ); - } - - final DataSource unpooled = DataSources.unpooledDataSource( jdbcUrl, connectionProps ); - - final Map allProps = new HashMap<>(); - allProps.putAll( props ); - allProps.putAll( PropertiesHelper.map(c3props) ); - - ds = DataSources.pooledDataSource( unpooled, allProps ); - } - catch (Exception e) { - ConnectionInfoLogger.INSTANCE.unableToInstantiateConnectionPool( e ); - throw new HibernateException( e ); } - isolation = ConnectionProviderInitiator.extractIsolation( props ); + setOverwriteProperty( C3P0_MIN_SIZE, C3P0_STYLE_MIN_POOL_SIZE, + hibernateProperties, c3p0Properties, minPoolSize ); + setOverwriteProperty( C3P0_MAX_SIZE, C3P0_STYLE_MAX_POOL_SIZE, + hibernateProperties, c3p0Properties, maxPoolSize ); + setOverwriteProperty( C3P0_TIMEOUT, C3P0_STYLE_MAX_IDLE_TIME, + hibernateProperties, c3p0Properties, maxIdleTime ); + setOverwriteProperty( C3P0_MAX_STATEMENTS, C3P0_STYLE_MAX_STATEMENTS, + hibernateProperties, c3p0Properties, maxStatements ); + setOverwriteProperty( C3P0_ACQUIRE_INCREMENT, C3P0_STYLE_ACQUIRE_INCREMENT, + hibernateProperties, c3p0Properties, acquireIncrement ); + setOverwriteProperty( C3P0_IDLE_TEST_PERIOD, C3P0_STYLE_IDLE_CONNECTION_TEST_PERIOD, + hibernateProperties, c3p0Properties, idleTestPeriod ); + + // revert to traditional behavior of setting initialPoolSize to minPoolSize + // unless otherwise specified with a c3p0.*-style parameter + final Integer initialPoolSize = getInteger( C3P0_STYLE_INITIAL_POOL_SIZE, hibernateProperties ); + if ( initialPoolSize == null ) { + setOverwriteProperty( "", C3P0_STYLE_INITIAL_POOL_SIZE, + hibernateProperties, c3p0Properties, minPoolSize ); + } - final Integer poolMinSize = minPoolSize; - final Integer poolMaxSize = maxPoolSize; - dbInfoProducer = (dialect) -> new DatabaseConnectionInfoImpl( - jdbcUrl, - jdbcDriverClass, - dialect.getVersion(), - Boolean.toString( autocommit ), - isolation != null ? ConnectionProviderInitiator.toIsolationNiceName( isolation ) : null, - poolMinSize, - poolMaxSize - ); + final Map aggregatedProperties = new HashMap<>(); + aggregatedProperties.putAll( hibernateProperties ); + aggregatedProperties.putAll( c3p0Properties ); + return aggregatedProperties; } @Override @@ -228,17 +255,17 @@ public DatabaseConnectionInfo getDatabaseConnectionInfo(Dialect dialect) { private void setOverwriteProperty( String hibernateStyleKey, String c3p0StyleKey, - Map hibp, - Properties c3p, + Map hibernateProperties, + Map c3p0Properties, Integer value) { if ( value != null ) { final String peeledC3p0Key = c3p0StyleKey.substring( 5 ); - c3p.put( peeledC3p0Key, String.valueOf( value ).trim() ); - if ( hibp.containsKey( c3p0StyleKey ) ) { + c3p0Properties.put( peeledC3p0Key, String.valueOf( value ).trim() ); + if ( hibernateProperties.containsKey( c3p0StyleKey ) ) { warnPropertyConflict( hibernateStyleKey, c3p0StyleKey ); } final String longC3p0StyleKey = "hibernate." + c3p0StyleKey; - if ( hibp.containsKey( longC3p0StyleKey ) ) { + if ( hibernateProperties.containsKey( longC3p0StyleKey ) ) { warnPropertyConflict( hibernateStyleKey, longC3p0StyleKey ); } } @@ -250,26 +277,15 @@ private void warnPropertyConflict(String hibernateStyle, String c3p0Style) { @Override public void stop() { - ConnectionInfoLogger.INSTANCE.cleaningUpConnectionPool( C3p0Settings.C3P0_CONFIG_PREFIX ); + ConnectionInfoLogger.INSTANCE.cleaningUpConnectionPool( C3P0_CONFIG_PREFIX ); try { - DataSources.destroy( ds ); + DataSources.destroy( dataSource ); } catch (SQLException sqle) { ConnectionInfoLogger.INSTANCE.unableToDestroyConnectionPool( sqle ); } } - /** - * Close the provider. - * - * @deprecated Use {@link #stop} instead - */ - @SuppressWarnings("unused") - @Deprecated - public void close() { - stop(); - } - @Override public void injectServices(ServiceRegistryImplementor serviceRegistry) { this.serviceRegistry = serviceRegistry; diff --git a/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/C3P0MessageLogger.java b/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/C3P0MessageLogger.java index bd98ab0e12f6..2d0b80dd0f3c 100644 --- a/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/C3P0MessageLogger.java +++ b/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/C3P0MessageLogger.java @@ -41,7 +41,7 @@ public interface C3P0MessageLogger extends ConnectionInfoLogger { * @param c3p0Style The {@code c3p0.} prefixed setting */ @LogMessage(level = WARN) - @Message(value = "Both hibernate-style property '%1$s' and c3p0-style property '%2$s' have been set in Hibernate " - + "properties. Hibernate-style property '%1$s' will be used and c3p0-style property '%2$s' will be ignored!", id = 10001) + @Message(value = "Both hibernate-style property '%1$s' and c3p0-style property '%2$s' have been set in Hibernate properties.\n" + + "Hibernate-style property '%1$s' will be used and c3p0-style property '%2$s' will be ignored", id = 10001) void bothHibernateAndC3p0StylesSet(String hibernateStyle,String c3p0Style); } diff --git a/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/StrategyRegistrationProviderImpl.java b/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/StrategyRegistrationProviderImpl.java index f2e9f273990f..f2a83e067ee7 100644 --- a/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/StrategyRegistrationProviderImpl.java +++ b/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/StrategyRegistrationProviderImpl.java @@ -20,7 +20,6 @@ public final class StrategyRegistrationProviderImpl implements StrategyRegistrationProvider { @Override - @SuppressWarnings("unchecked") public Iterable getStrategyRegistrations() { final SimpleStrategyRegistrationImpl c3p0 = new SimpleStrategyRegistrationImpl<>( ConnectionProvider.class, diff --git a/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0ProxyConnectionProvider.java b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0ProxyConnectionProvider.java index 072a7f8b555d..49b91fcd9192 100644 --- a/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0ProxyConnectionProvider.java +++ b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0ProxyConnectionProvider.java @@ -48,7 +48,7 @@ public void configure(Map props) { throw new IllegalStateException( e ); } - ReflectionUtil.setField( this, "ds", dataSource ); + ReflectionUtil.setField( this, "dataSource", dataSource ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/JdbcSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/JdbcSettings.java index 28ba5645da0a..909d56ec8e8d 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/JdbcSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/JdbcSettings.java @@ -240,11 +240,12 @@ public interface JdbcSettings extends C3p0Settings, AgroalSettings, HikariCPSett String CONNECTION_PROVIDER = "hibernate.connection.provider_class"; /** - * Specifies the maximum number of inactive connections for the built-in - * {@linkplain org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl - * connection pool}. - * - * @settingDefault 20 + * Specifies the maximum number of inactive connections for any + * {@linkplain ConnectionProvider connection pool} which respects this + * setting, including every built-in implementation except for + * {@link org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl}. + *

+ * The default pool size depends on the connection provider. */ String POOL_SIZE = "hibernate.connection.pool_size"; diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/internal/ConnectionProviderInitiator.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/internal/ConnectionProviderInitiator.java index 00f8d5ee7be9..6f2a470b282f 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/internal/ConnectionProviderInitiator.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/internal/ConnectionProviderInitiator.java @@ -17,9 +17,9 @@ import org.hibernate.boot.registry.StandardServiceInitiator; import org.hibernate.boot.registry.selector.spi.StrategySelector; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; +import org.hibernate.engine.jdbc.connections.spi.ConnectionProviderConfigurationException; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; -import org.hibernate.internal.util.StringHelper; import org.hibernate.resource.beans.container.spi.BeanContainer; import org.hibernate.resource.beans.internal.Helper; import org.hibernate.service.spi.ServiceRegistryImplementor; @@ -43,6 +43,7 @@ import static org.hibernate.cfg.JdbcSettings.USER; import static org.hibernate.cfg.SchemaToolingSettings.ENABLE_SYNONYMS; import static org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentImpl.isMultiTenancyEnabled; +import static org.hibernate.internal.util.StringHelper.isBlank; import static org.hibernate.internal.util.StringHelper.nullIfEmpty; /** @@ -325,29 +326,38 @@ public static Integer interpretIsolation(Object setting) { return null; } else if ( setting instanceof Number number ) { - return number.intValue(); + final int isolationLevel = number.intValue(); + checkIsolationLevel( isolationLevel ); + return isolationLevel; } else { final String string = setting.toString(); - if ( StringHelper.isEmpty( string ) ) { + if ( isBlank( string ) ) { return null; } else if ( ISOLATION_VALUE_MAP.containsKey( string ) ) { return ISOLATION_VALUE_MAP.get( string ); } else { - // it could be a String representation of the isolation numeric value... + // it could be a String representation of the isolation numeric value try { - return Integer.valueOf( string ); + final int isolationLevel = Integer.parseInt( string ); + checkIsolationLevel( isolationLevel ); + return isolationLevel; } catch (NumberFormatException ignore) { + throw new ConnectionProviderConfigurationException( "Unknown transaction isolation level: '" + string + "'" ); } - - throw new HibernateException("Could not interpret transaction isolation setting [" + setting + "]"); } } } + private static void checkIsolationLevel(int isolationLevel) { + if ( !ISOLATION_VALUE_CONSTANT_NAME_MAP.containsKey( isolationLevel ) ) { + throw new ConnectionProviderConfigurationException( "Unknown transaction isolation level: " + isolationLevel ); + } + } + /** * Gets the {@link Connection} constant name corresponding to the given isolation. * @@ -399,8 +409,9 @@ public interface SettingConsumer { public static void consumeSetting(Map settings, SettingConsumer consumer, String... names) { for ( String name : names ) { - if ( settings.containsKey(name) ) { - consumer.consumeSetting( name, (String) settings.get(name) ); + final Object setting = settings.get( name ); + if ( setting != null ) { + consumer.consumeSetting( name, setting.toString() ); return; } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/internal/DatasourceConnectionProviderImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/internal/DatasourceConnectionProviderImpl.java index 2ecd5e5fd46a..547c80de115e 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/internal/DatasourceConnectionProviderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/internal/DatasourceConnectionProviderImpl.java @@ -14,6 +14,7 @@ import org.hibernate.cfg.JdbcSettings; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; +import org.hibernate.engine.jdbc.connections.spi.ConnectionProviderConfigurationException; import org.hibernate.engine.jdbc.connections.spi.DatabaseConnectionInfo; import org.hibernate.engine.jndi.spi.JndiService; import org.hibernate.internal.log.ConnectionInfoLogger; @@ -70,7 +71,7 @@ public boolean isUnwrappableAs(Class unwrapType) { } @Override - @SuppressWarnings( {"unchecked"}) + @SuppressWarnings("unchecked") public T unwrap(Class unwrapType) { if ( ConnectionProvider.class.equals( unwrapType ) || DatasourceConnectionProviderImpl.class.isAssignableFrom( unwrapType ) ) { @@ -88,26 +89,23 @@ else if ( DataSource.class.isAssignableFrom( unwrapType ) ) { public void configure(Map configValues) { if ( dataSource == null ) { final Object dataSourceSetting = configValues.get( DATASOURCE ); - if ( dataSourceSetting instanceof DataSource ds ) { - dataSource = ds; + if ( dataSourceSetting instanceof DataSource instance ) { + dataSource = instance; } - else { - final String dataSourceJndiName = (String) dataSourceSetting; - if ( dataSourceJndiName == null ) { - throw new HibernateException( - "DataSource to use was not injected nor specified by [" + DATASOURCE - + "] configuration property" - ); - } - this.dataSourceJndiName = dataSourceJndiName; + else if ( dataSourceSetting instanceof String jndiName ) { + dataSourceJndiName = jndiName; if ( jndiService == null ) { - throw new HibernateException( "Unable to locate JndiService to lookup Datasource" ); + throw new ConnectionProviderConfigurationException( "Unable to locate JndiService to lookup Datasource" ); } - dataSource = (DataSource) jndiService.locate( dataSourceJndiName ); + dataSource = (DataSource) jndiService.locate( jndiName ); + } + else { + throw new ConnectionProviderConfigurationException( + "DataSource to use was not injected nor specified by '" + DATASOURCE + "'" ); } } if ( dataSource == null ) { - throw new HibernateException( "Unable to determine appropriate DataSource to use" ); + throw new ConnectionProviderConfigurationException( "Unable to determine appropriate DataSource to use" ); } if ( configValues.containsKey( AvailableSettings.AUTOCOMMIT ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/internal/DriverManagerConnectionProviderImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/internal/DriverManagerConnectionProviderImpl.java index 90e3adb28102..b640b51d1007 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/internal/DriverManagerConnectionProviderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/internal/DriverManagerConnectionProviderImpl.java @@ -28,6 +28,7 @@ import org.hibernate.dialect.Dialect; import org.hibernate.dialect.SimpleDatabaseVersion; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; +import org.hibernate.engine.jdbc.connections.spi.ConnectionProviderConfigurationException; import org.hibernate.engine.jdbc.connections.spi.DatabaseConnectionInfo; import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.service.UnknownUnwrapTypeException; @@ -90,11 +91,8 @@ private PooledConnections buildPool(Map configurationValues, Serv final int maxSize = ConfigurationHelper.getInt( AvailableSettings.POOL_SIZE, configurationValues, 20 ); final int initialSize = ConfigurationHelper.getInt( INITIAL_SIZE, configurationValues, minSize ); - ConnectionCreator connectionCreator = buildCreator( configurationValues, serviceRegistry ); - PooledConnections.Builder pooledConnectionBuilder = new PooledConnections.Builder( - connectionCreator, - autoCommit - ); + final ConnectionCreator creator = buildCreator( configurationValues, serviceRegistry ); + final PooledConnections.Builder pooledConnectionBuilder = new PooledConnections.Builder( creator, autoCommit ); pooledConnectionBuilder.initialSize( initialSize ); pooledConnectionBuilder.minSize( minSize ); pooledConnectionBuilder.maxSize( maxSize ); @@ -102,8 +100,9 @@ private PooledConnections buildPool(Map configurationValues, Serv return pooledConnectionBuilder.build(); } - private static ConnectionCreator buildCreator(Map configurationValues, ServiceRegistryImplementor serviceRegistry) { - final String url = (String) configurationValues.get( AvailableSettings.URL ); + private static ConnectionCreator buildCreator( + Map configurationValues, ServiceRegistryImplementor serviceRegistry) { + final String url = jdbcUrl( configurationValues ); String driverClassName = (String) configurationValues.get( AvailableSettings.DRIVER ); boolean success = false; @@ -112,14 +111,14 @@ private static ConnectionCreator buildCreator(Map configurationVa driver = loadDriverIfPossible( driverClassName, serviceRegistry ); success = true; } - else if ( url != null ) { + else { //try to guess the driver class from the JDBC URL for ( Database database: Database.values() ) { if ( database.matchesUrl( url ) ) { driverClassName = database.getDriverClassName( url ); if ( driverClassName != null ) { try { - loadDriverIfPossible(driverClassName, serviceRegistry); + loadDriverIfPossible( driverClassName, serviceRegistry ); success = true; } catch (Exception e) { @@ -132,22 +131,7 @@ else if ( url != null ) { } } - StringBuilder list = new StringBuilder(); - if ( !success ) { - //we're hoping that the driver is already loaded - ConnectionInfoLogger.INSTANCE.jdbcDriverNotSpecified(); - Enumeration drivers = DriverManager.getDrivers(); - while ( drivers.hasMoreElements() ) { - if ( list.length() != 0) { - list.append(", "); - } - list.append( drivers.nextElement().getClass().getName() ); - } - } - - if ( url == null ) { - throw new HibernateException( "No JDBC URL specified by property " + JAKARTA_JDBC_URL ); - } + final String driverList = success ? driverClassName : driverList(); final Properties connectionProps = ConnectionProviderInitiator.getConnectionProperties( configurationValues ); @@ -155,26 +139,16 @@ else if ( url != null ) { final Integer isolation = ConnectionProviderInitiator.extractIsolation( configurationValues ); final String initSql = (String) configurationValues.get( INIT_SQL ); - final Object connectionCreatorFactory = configurationValues.get( CONNECTION_CREATOR_FACTORY ); - ConnectionCreatorFactory factory = null; - if ( connectionCreatorFactory instanceof ConnectionCreatorFactory ) { - factory = (ConnectionCreatorFactory) connectionCreatorFactory; - } - else if ( connectionCreatorFactory != null ) { - factory = loadConnectionCreatorFactory( connectionCreatorFactory.toString(), serviceRegistry ); - } - if ( factory == null ) { - factory = ConnectionCreatorFactoryImpl.INSTANCE; - } + final ConnectionCreatorFactory factory = getConnectionCreatorFactory( configurationValues, serviceRegistry ); dbInfo = new DatabaseConnectionInfoImpl( url, - success ? driverClassName : list.toString(), + driverList, SimpleDatabaseVersion.ZERO_VERSION, Boolean.toString( autoCommit ), - isolation != null ? ConnectionProviderInitiator.toIsolationNiceName(isolation) : null, - ConfigurationHelper.getInt(MIN_SIZE, configurationValues, 1), - ConfigurationHelper.getInt(AvailableSettings.POOL_SIZE, configurationValues, 20) + isolation != null ? ConnectionProviderInitiator.toIsolationNiceName( isolation ) : null, + ConfigurationHelper.getInt( MIN_SIZE, configurationValues, 1 ), + ConfigurationHelper.getInt( AvailableSettings.POOL_SIZE, configurationValues, 20 ) ); return factory.create( @@ -189,15 +163,53 @@ else if ( connectionCreatorFactory != null ) { ); } + private static String driverList() { + //we're hoping that the driver is already loaded + ConnectionInfoLogger.INSTANCE.jdbcDriverNotSpecified(); + final StringBuilder list = new StringBuilder(); + final Enumeration drivers = DriverManager.getDrivers(); + while ( drivers.hasMoreElements() ) { + if ( !list.isEmpty() ) { + list.append(", "); + } + list.append( drivers.nextElement().getClass().getName() ); + } + return list.toString(); + } + + private static String jdbcUrl(Map configurationValues) { + final String url = (String) configurationValues.get( AvailableSettings.URL ); + if ( url == null ) { + throw new ConnectionProviderConfigurationException( "No JDBC URL specified by property '" + JAKARTA_JDBC_URL + "'" ); + } + return url; + } + + private static ConnectionCreatorFactory getConnectionCreatorFactory( + Map configurationValues, ServiceRegistryImplementor serviceRegistry) { + final Object connectionCreatorFactory = configurationValues.get( CONNECTION_CREATOR_FACTORY ); + final ConnectionCreatorFactory factory; + if ( connectionCreatorFactory instanceof ConnectionCreatorFactory instance ) { + factory = instance; + } + else if ( connectionCreatorFactory != null ) { + factory = loadConnectionCreatorFactory( connectionCreatorFactory.toString(), serviceRegistry ); + } + else { + factory = null; + } + return factory == null ? ConnectionCreatorFactoryImpl.INSTANCE : factory; + } + private static Driver loadDriverIfPossible(String driverClassName, ServiceRegistryImplementor serviceRegistry) { if ( driverClassName == null ) { ConnectionInfoLogger.INSTANCE.debug( "No driver class specified" ); return null; } - - if ( serviceRegistry != null ) { - final ClassLoaderService classLoaderService = serviceRegistry.requireService( ClassLoaderService.class ); - final Class driverClass = classLoaderService.classForName( driverClassName ); + else if ( serviceRegistry != null ) { + final Class driverClass = + serviceRegistry.requireService( ClassLoaderService.class ) + .classForName( driverClassName ); try { return driverClass.newInstance(); } @@ -205,22 +217,23 @@ private static Driver loadDriverIfPossible(String driverClassName, ServiceRegist throw new ServiceException( "Specified JDBC Driver " + driverClassName + " could not be loaded", e ); } } - - try { - return (Driver) Class.forName( driverClassName ).newInstance(); - } - catch ( Exception e1 ) { - throw new ServiceException( "Specified JDBC Driver " + driverClassName + " could not be loaded", e1 ); + else { + try { + return (Driver) Class.forName( driverClassName ).newInstance(); + } + catch (Exception e1) { + throw new ServiceException( "Specified JDBC Driver " + driverClassName + " could not be loaded", e1 ); + } } } - private static ConnectionCreatorFactory loadConnectionCreatorFactory(String connectionCreatorFactoryClassName, ServiceRegistryImplementor serviceRegistry) { + private static ConnectionCreatorFactory loadConnectionCreatorFactory( + String connectionCreatorFactoryClassName, ServiceRegistryImplementor serviceRegistry) { if ( connectionCreatorFactoryClassName == null ) { ConnectionInfoLogger.INSTANCE.debug( "No connection creator factory class specified" ); return null; } - - if ( serviceRegistry != null ) { + else if ( serviceRegistry != null ) { final ClassLoaderService classLoaderService = serviceRegistry.requireService( ClassLoaderService.class ); final Class factoryClass = classLoaderService.classForName( connectionCreatorFactoryClassName ); @@ -231,12 +244,15 @@ private static ConnectionCreatorFactory loadConnectionCreatorFactory(String conn throw new ServiceException( "Specified ConnectionCreatorFactory " + connectionCreatorFactoryClassName + " could not be loaded", e ); } } - - try { - return (ConnectionCreatorFactory) Class.forName( connectionCreatorFactoryClassName ).newInstance(); - } - catch ( Exception e1 ) { - throw new ServiceException( "Specified ConnectionCreatorFactory " + connectionCreatorFactoryClassName + " could not be loaded", e1 ); + else { + try { + return (ConnectionCreatorFactory) Class.forName( connectionCreatorFactoryClassName ).newInstance(); + } + catch (Exception e1) { + throw new ServiceException( + "Specified ConnectionCreatorFactory " + connectionCreatorFactoryClassName + " could not be loaded", + e1 ); + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/spi/ConnectionProviderConfigurationException.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/spi/ConnectionProviderConfigurationException.java new file mode 100644 index 000000000000..d17ded15aa40 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/spi/ConnectionProviderConfigurationException.java @@ -0,0 +1,23 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.engine.jdbc.connections.spi; + +import org.hibernate.HibernateException; + +/** + * Occurs when there is a problem configuring a {@link ConnectionProvider}. + * + * @since 7.0 + * + * @author Gavin King + */ +public class ConnectionProviderConfigurationException extends HibernateException { + public ConnectionProviderConfigurationException(String message) { + super( message ); + } + public ConnectionProviderConfigurationException(String message, Throwable cause) { + super( message, cause ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/internal/log/ConnectionInfoLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/log/ConnectionInfoLogger.java index d5ade897b282..f6c6eea9ece1 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/log/ConnectionInfoLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/log/ConnectionInfoLogger.java @@ -66,7 +66,7 @@ public interface ConnectionInfoLogger extends BasicLogger { void unableToDestroyConnectionPool(@Cause Exception e); @LogMessage(level = DEBUG) - @Message(value = "Could not instantiate connection pool", id = 10001011) + @Message(value = "Could not create connection pool", id = 10001011) void unableToInstantiateConnectionPool(@Cause Exception e); @LogMessage(level = DEBUG) diff --git a/hibernate-hikaricp/src/main/java/org/hibernate/hikaricp/internal/HikariCPConnectionProvider.java b/hibernate-hikaricp/src/main/java/org/hibernate/hikaricp/internal/HikariCPConnectionProvider.java index a4f6b073b4ef..16ab7c8b777e 100644 --- a/hibernate-hikaricp/src/main/java/org/hibernate/hikaricp/internal/HikariCPConnectionProvider.java +++ b/hibernate-hikaricp/src/main/java/org/hibernate/hikaricp/internal/HikariCPConnectionProvider.java @@ -4,8 +4,8 @@ */ package org.hibernate.hikaricp.internal; +import java.io.Serial; import java.sql.Connection; -import java.sql.DatabaseMetaData; import java.sql.SQLException; import javax.sql.DataSource; import java.util.Map; @@ -14,9 +14,9 @@ import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.connections.internal.DatabaseConnectionInfoImpl; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; +import org.hibernate.engine.jdbc.connections.spi.ConnectionProviderConfigurationException; import org.hibernate.engine.jdbc.connections.spi.DatabaseConnectionInfo; import org.hibernate.internal.log.ConnectionInfoLogger; -import org.hibernate.internal.util.StringHelper; import org.hibernate.service.UnknownUnwrapTypeException; import org.hibernate.service.spi.Configurable; import org.hibernate.service.spi.Stoppable; @@ -25,45 +25,51 @@ import com.zaxxer.hikari.HikariDataSource; import static org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.allowJdbcMetadataAccess; +import static org.hibernate.hikaricp.internal.HikariConfigurationUtil.loadConfiguration; +import static org.hibernate.internal.util.StringHelper.isBlank; /** - * HikariCP Connection provider for Hibernate. + * {@link ConnectionProvider} based on HikariCP connection pool. + *

+ * To force the use of this {@code ConnectionProvider} set + * {@value org.hibernate.cfg.JdbcSettings#CONNECTION_PROVIDER} + * to {@code hikari} or {@code hikaricp}. * * @author Brett Wooldridge * @author Luca Burgazzoli */ public class HikariCPConnectionProvider implements ConnectionProvider, Configurable, Stoppable { + @Serial private static final long serialVersionUID = -9131625057941275711L; private boolean isMetadataAccessAllowed = true; /** * HikariCP configuration. */ - private HikariConfig hcfg = null; + private HikariConfig hikariConfig = null; /** * HikariCP data source. */ - private HikariDataSource hds = null; + private HikariDataSource hikariDataSource = null; // ************************************************************************* // Configurable // ************************************************************************* @Override - public void configure(Map props) throws HibernateException { + public void configure(Map configurationValues) throws HibernateException { try { - isMetadataAccessAllowed = allowJdbcMetadataAccess( props ); - + isMetadataAccessAllowed = allowJdbcMetadataAccess( configurationValues ); ConnectionInfoLogger.INSTANCE.configureConnectionPool( "HikariCP" ); - - hcfg = HikariConfigurationUtil.loadConfiguration( props ); - hds = new HikariDataSource( hcfg ); + hikariConfig = loadConfiguration( configurationValues ); + hikariDataSource = new HikariDataSource( hikariConfig ); } catch (Exception e) { ConnectionInfoLogger.INSTANCE.unableToInstantiateConnectionPool( e ); - throw new HibernateException( e ); + throw new ConnectionProviderConfigurationException( + "Could not configure HikariCP: " + e.getMessage(), e ); } } @@ -73,7 +79,7 @@ public void configure(Map props) throws HibernateException { @Override public Connection getConnection() throws SQLException { - return hds != null ? hds.getConnection() : null; + return hikariDataSource != null ? hikariDataSource.getConnection() : null; } @Override @@ -89,23 +95,24 @@ public boolean supportsAggressiveRelease() { @Override public DatabaseConnectionInfo getDatabaseConnectionInfo(Dialect dialect) { return new DatabaseConnectionInfoImpl( - hcfg.getJdbcUrl(), + hikariConfig.getJdbcUrl(), // Attempt to resolve the driver name from the dialect, in case it wasn't explicitly set and access to // the database metadata is allowed - !StringHelper.isBlank( hcfg.getDriverClassName() ) ? hcfg.getDriverClassName() : extractDriverNameFromMetadata(), + isBlank( hikariConfig.getDriverClassName() ) + ? extractDriverNameFromMetadata() + : hikariConfig.getDriverClassName(), dialect.getVersion(), - Boolean.toString( hcfg.isAutoCommit() ), - hcfg.getTransactionIsolation(), - hcfg.getMinimumIdle(), - hcfg.getMaximumPoolSize() + Boolean.toString( hikariConfig.isAutoCommit() ), + hikariConfig.getTransactionIsolation(), + hikariConfig.getMinimumIdle(), + hikariConfig.getMaximumPoolSize() ); } private String extractDriverNameFromMetadata() { - if (isMetadataAccessAllowed) { + if ( isMetadataAccessAllowed ) { try ( Connection conn = getConnection() ) { - DatabaseMetaData dbmd = conn.getMetaData(); - return dbmd.getDriverName(); + return conn.getMetaData().getDriverName(); } catch (SQLException e) { // Do nothing @@ -129,7 +136,7 @@ public T unwrap(Class unwrapType) { return (T) this; } else if ( DataSource.class.isAssignableFrom( unwrapType ) ) { - return (T) hds; + return (T) hikariDataSource; } else { throw new UnknownUnwrapTypeException( unwrapType ); @@ -142,9 +149,9 @@ else if ( DataSource.class.isAssignableFrom( unwrapType ) ) { @Override public void stop() { - if ( hds != null ) { + if ( hikariDataSource != null ) { ConnectionInfoLogger.INSTANCE.cleaningUpConnectionPool( "HikariCP" ); - hds.close(); + hikariDataSource.close(); } } } diff --git a/hibernate-hikaricp/src/main/java/org/hibernate/hikaricp/internal/HikariConfigurationUtil.java b/hibernate-hikaricp/src/main/java/org/hibernate/hikaricp/internal/HikariConfigurationUtil.java index 3ec65b9f3c41..6e99cbe589fa 100644 --- a/hibernate-hikaricp/src/main/java/org/hibernate/hikaricp/internal/HikariConfigurationUtil.java +++ b/hibernate-hikaricp/src/main/java/org/hibernate/hikaricp/internal/HikariConfigurationUtil.java @@ -7,7 +7,6 @@ import java.util.Map; import java.util.Properties; -import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.HikariCPSettings; import org.hibernate.cfg.JdbcSettings; import org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator; @@ -29,15 +28,17 @@ public class HikariConfigurationUtil { /** * Create/load a HikariConfig from Hibernate properties. * - * @param props a map of Hibernate properties + * @param properties a map of Hibernate properties * @return a HikariConfig */ - public static HikariConfig loadConfiguration(Map props) { - Properties hikariProps = new Properties(); - copyProperty( JdbcSettings.AUTOCOMMIT, props, "autoCommit", hikariProps ); + public static HikariConfig loadConfiguration(Map properties) { + final Properties hikariProps = new Properties(); + copyProperty( JdbcSettings.AUTOCOMMIT, properties, "autoCommit", hikariProps ); + + copyProperty( JdbcSettings.POOL_SIZE, properties, "maximumPoolSize", hikariProps ); copyProperty( - props, + properties, "driverClassName", hikariProps, JdbcSettings.JAKARTA_JDBC_DRIVER, @@ -46,7 +47,7 @@ public static HikariConfig loadConfiguration(Map props) { ); copyProperty( - props, + properties, "jdbcUrl", hikariProps, JdbcSettings.JAKARTA_JDBC_URL, @@ -55,7 +56,7 @@ public static HikariConfig loadConfiguration(Map props) { ); copyProperty( - props, + properties, "username", hikariProps, JdbcSettings.JAKARTA_JDBC_USER, @@ -64,19 +65,20 @@ public static HikariConfig loadConfiguration(Map props) { ); copyProperty( - props, + properties, "password", hikariProps, - AvailableSettings.JAKARTA_JDBC_PASSWORD, - AvailableSettings.PASS, - AvailableSettings.JPA_JDBC_PASSWORD + JdbcSettings.JAKARTA_JDBC_PASSWORD, + JdbcSettings.PASS, + JdbcSettings.JPA_JDBC_PASSWORD ); - copyIsolationSetting( props, hikariProps ); + copyIsolationSetting( properties, hikariProps ); - for ( String key : props.keySet() ) { + for ( var entry : properties.entrySet() ) { + final String key = entry.getKey(); if ( key.startsWith( CONFIG_PREFIX ) ) { - hikariProps.setProperty( key.substring( CONFIG_PREFIX.length() ), (String) props.get( key ) ); + hikariProps.setProperty( key.substring( CONFIG_PREFIX.length() ), entry.getValue().toString() ); } } @@ -85,7 +87,7 @@ public static HikariConfig loadConfiguration(Map props) { private static void copyProperty(String srcKey, Map src, String dstKey, Properties dst) { if ( src.containsKey( srcKey ) ) { - dst.setProperty( dstKey, (String) src.get( srcKey ) ); + dst.setProperty( dstKey, src.get( srcKey ).toString() ); } } @@ -100,10 +102,8 @@ private static void copyProperty(Map src, String dstKey, Properti private static void copyIsolationSetting(Map props, Properties hikariProps) { final Integer isolation = ConnectionProviderInitiator.extractIsolation( props ); if ( isolation != null ) { - hikariProps.put( - "transactionIsolation", - ConnectionProviderInitiator.toIsolationConnectionConstantName( isolation ) - ); + hikariProps.put( "transactionIsolation", + ConnectionProviderInitiator.toIsolationConnectionConstantName( isolation ) ); } } diff --git a/hibernate-hikaricp/src/main/java/org/hibernate/hikaricp/internal/StrategyRegistrationProviderImpl.java b/hibernate-hikaricp/src/main/java/org/hibernate/hikaricp/internal/StrategyRegistrationProviderImpl.java index 0021d64f51ce..44416a7ebf04 100644 --- a/hibernate-hikaricp/src/main/java/org/hibernate/hikaricp/internal/StrategyRegistrationProviderImpl.java +++ b/hibernate-hikaricp/src/main/java/org/hibernate/hikaricp/internal/StrategyRegistrationProviderImpl.java @@ -20,7 +20,6 @@ public final class StrategyRegistrationProviderImpl implements StrategyRegistrationProvider { @Override - @SuppressWarnings("unchecked") public Iterable getStrategyRegistrations() { final SimpleStrategyRegistrationImpl strategyRegistration = new SimpleStrategyRegistrationImpl<>( ConnectionProvider.class, diff --git a/hibernate-ucp/src/main/java/org/hibernate/oracleucp/internal/StrategyRegistrationProviderImpl.java b/hibernate-ucp/src/main/java/org/hibernate/oracleucp/internal/StrategyRegistrationProviderImpl.java index cbac650b60b4..4da10b815013 100644 --- a/hibernate-ucp/src/main/java/org/hibernate/oracleucp/internal/StrategyRegistrationProviderImpl.java +++ b/hibernate-ucp/src/main/java/org/hibernate/oracleucp/internal/StrategyRegistrationProviderImpl.java @@ -19,7 +19,7 @@ */ public class StrategyRegistrationProviderImpl implements StrategyRegistrationProvider { private static final List REGISTRATIONS = Collections.singletonList( - (StrategyRegistration) new SimpleStrategyRegistrationImpl( + new SimpleStrategyRegistrationImpl<>( ConnectionProvider.class, UCPConnectionProvider.class, "ucp", @@ -30,7 +30,6 @@ public class StrategyRegistrationProviderImpl implements StrategyRegistrationPro ); @Override - @SuppressWarnings("unchecked") public Iterable getStrategyRegistrations() { return REGISTRATIONS; } diff --git a/hibernate-ucp/src/main/java/org/hibernate/oracleucp/internal/UCPConnectionProvider.java b/hibernate-ucp/src/main/java/org/hibernate/oracleucp/internal/UCPConnectionProvider.java index def0fcecfe7e..871f77192792 100644 --- a/hibernate-ucp/src/main/java/org/hibernate/oracleucp/internal/UCPConnectionProvider.java +++ b/hibernate-ucp/src/main/java/org/hibernate/oracleucp/internal/UCPConnectionProvider.java @@ -4,6 +4,7 @@ */ package org.hibernate.oracleucp.internal; +import java.io.Serial; import java.lang.reflect.Method; import java.sql.Connection; import java.sql.SQLException; @@ -20,6 +21,7 @@ import org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator; import org.hibernate.engine.jdbc.connections.internal.DatabaseConnectionInfoImpl; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; +import org.hibernate.engine.jdbc.connections.spi.ConnectionProviderConfigurationException; import org.hibernate.engine.jdbc.connections.spi.DatabaseConnectionInfo; import org.hibernate.internal.log.ConnectionInfoLogger; import org.hibernate.internal.util.config.ConfigurationHelper; @@ -36,32 +38,32 @@ public class UCPConnectionProvider implements ConnectionProvider, Configurable, Stoppable { + @Serial private static final long serialVersionUID = 1L; private PoolDataSource ucpDS = null; - private UniversalConnectionPoolManager poolManager = null; private static final String UCP_CONFIG_PREFIX = "hibernate.oracleucp"; private static final String CONFIG_PREFIX = UCP_CONFIG_PREFIX + "."; private boolean autoCommit; private Integer isolation; - @SuppressWarnings("rawtypes") @Override - public void configure(Map props) throws HibernateException { + public void configure(Map props) throws HibernateException { try { ConnectionInfoLogger.INSTANCE.configureConnectionPool( "Ucp" ); isolation = ConnectionProviderInitiator.extractIsolation( props ); autoCommit = ConfigurationHelper.getBoolean( AvailableSettings.AUTOCOMMIT, props ); - UniversalConnectionPoolManager poolManager = UniversalConnectionPoolManagerImpl. - getUniversalConnectionPoolManager(); + UniversalConnectionPoolManager poolManager = + UniversalConnectionPoolManagerImpl.getUniversalConnectionPoolManager(); ucpDS = PoolDataSourceFactory.getPoolDataSource(); Properties ucpProps = getConfiguration(props); configureDataSource(ucpDS, ucpProps); } catch (Exception e) { ConnectionInfoLogger.INSTANCE.unableToInstantiateConnectionPool( e ); - throw new HibernateException( e ); + throw new ConnectionProviderConfigurationException( + "Could not configure UCP: " + e.getMessage(), e ); } } @@ -128,13 +130,11 @@ private Properties getConfiguration(Map props) { copyProperty( AvailableSettings.USER, props, "user", ucpProps ); copyProperty( AvailableSettings.PASS, props, "password", ucpProps ); - for ( Object keyo : props.keySet() ) { - if ( !(keyo instanceof String) ) { - continue; - } - String key = (String) keyo; - if ( key.startsWith( CONFIG_PREFIX ) ) { - ucpProps.setProperty( key.substring( CONFIG_PREFIX.length() ), (String) props.get( key ) ); + for ( Object object : props.keySet() ) { + if ( object instanceof String key ) { + if ( key.startsWith( CONFIG_PREFIX ) ) { + ucpProps.setProperty( key.substring( CONFIG_PREFIX.length() ), (String) props.get( key ) ); + } } }