Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/
package org.hibernate.agroal.internal;

import java.io.Serial;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.DatabaseMetaData;
Expand All @@ -19,6 +20,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.service.UnknownUnwrapTypeException;
Expand All @@ -33,14 +35,18 @@
import io.agroal.api.security.NamePrincipal;
import io.agroal.api.security.SimplePassword;

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: <pre> hibernate.connection.provider_class AgroalConnectionProvider </pre>
*
* Usual hibernate properties are supported:
* {@link ConnectionProvider} based on Agroal connection pool.
* <p>
* To force the use of this {@code ConnectionProvider} set
* {@value org.hibernate.cfg.JdbcSettings#CONNECTION_PROVIDER}
* to {@code agroal}.
* <p>
* Usual hibernate connection properties are supported:
* <pre>
* hibernate.connection.driver_class
* hibernate.connection.url
Expand All @@ -49,8 +55,8 @@
* hibernate.connection.autocommit
* hibernate.connection.isolation
* </pre>
*
* Other configuration options are available, using the {@code hibernate.agroal} prefix
* <p>
* Other configuration options are available, using the {@code hibernate.agroal} prefix.
*
* @see AgroalSettings
* @see AgroalPropertiesReader
Expand All @@ -61,14 +67,16 @@
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;

// --- Configurable

private static String extractIsolationAsString(Map<String, Object> properties) {
Integer isolation = ConnectionProviderInitiator.extractIsolation( properties );
final Integer isolation = ConnectionProviderInitiator.extractIsolation( properties );
if ( isolation != null ) {
// Agroal resolves transaction isolation from the 'nice' name
return ConnectionProviderInitiator.toIsolationNiceName( isolation );
Expand All @@ -77,45 +85,51 @@ private static String extractIsolationAsString(Map<String, Object> properties) {
}

private static void resolveIsolationSetting(Map<String, Object> properties, AgroalConnectionFactoryConfigurationSupplier cf) {
String isolationString = extractIsolationAsString( properties );
final String isolationString = extractIsolationAsString( properties );
if ( isolationString != null ) {
cf.jdbcTransactionIsolation( AgroalConnectionFactoryConfiguration.TransactionIsolation.valueOf( isolationString ) );
}
}

private static <T> void copyProperty(Map<String, Object> properties, String key, Consumer<T> consumer, Function<String, T> converter) {
Object value = properties.get( key );
if ( value instanceof String ) {
consumer.accept( converter.apply( (String) value ) );
final Object value = properties.get( key );
if ( value instanceof String string ) {
consumer.accept( converter.apply( string ) );
}
}

@Override
public void configure(Map<String, Object> props) throws HibernateException {
isMetadataAccessAllowed = allowJdbcMetadataAccess( props );
public void configure(Map<String, Object> 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
final AgroalPropertiesReader agroalProperties = new AgroalPropertiesReader( CONFIG_PREFIX )
.readProperties( toStringValuedProperties( properties ) );
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 );
copyProperty( properties, AvailableSettings.DRIVER, cf::connectionProviderClassName, Function.identity() );
copyProperty( properties, AvailableSettings.URL, cf::jdbcUrl, Function.identity() );
copyProperty( properties, AvailableSettings.USER, cf::principal, NamePrincipal::new );
copyProperty( properties, AvailableSettings.PASS, cf::credential, SimplePassword::new );
copyProperty( properties, AvailableSettings.AUTOCOMMIT, cf::autoCommit, Boolean::valueOf );
resolveIsolationSetting( properties, cf );
return cf;
} ) );

agroalDataSource = AgroalDataSource.from( agroalProperties );
}
catch ( Exception e ) {
ConnectionInfoLogger.INSTANCE.unableToInstantiateConnectionPool( e );
throw new HibernateException( e );
throw new ConnectionProviderConfigurationException(
"Could not configure Agroal: " + e.getMessage(), e );
}
}

private static Map<String,String> toStringValuedProperties(Map<String,Object> properties) {
return properties.entrySet().stream()
.collect( toMap( Map.Entry::getKey, e -> e.getValue().toString() ) );
}

// --- ConnectionProvider

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

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;
Expand All @@ -23,6 +22,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.PropertiesHelper;
Expand All @@ -38,8 +38,13 @@
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.
* <p>
* To force the use of this {@code ConnectionProvider} set
* {@value org.hibernate.cfg.JdbcSettings#CONNECTION_PROVIDER}
* to {@code c3p0}.
* <p>
* Hibernate selects this by default if the {@code hibernate.c3p0.*} properties are set.
*
* @author various people
* @see ConnectionProvider
Expand Down Expand Up @@ -141,8 +146,8 @@ public void configure(Map<String, Object> props) {
}
}

Integer minPoolSize = null;
Integer maxPoolSize = null;
final Integer minPoolSize;
final Integer maxPoolSize;
try {

//swaldman 2004-02-07: modify to allow null values to signify fall through to c3p0 PoolConfig defaults
Expand Down Expand Up @@ -197,7 +202,8 @@ public void configure(Map<String, Object> props) {
}
catch (Exception e) {
ConnectionInfoLogger.INSTANCE.unableToInstantiateConnectionPool( e );
throw new HibernateException( e );
throw new ConnectionProviderConfigurationException(
"Could not configure c3p0: " + e.getMessage(), e );
}

isolation = ConnectionProviderInitiator.extractIsolation( props );
Expand Down Expand Up @@ -259,17 +265,6 @@ public void stop() {
}
}

/**
* Close the provider.
*
* @deprecated Use {@link #stop} instead
*/
@SuppressWarnings("unused")
@Deprecated
public void close() {
stop();
}

@Override
public void injectServices(ServiceRegistryImplementor serviceRegistry) {
this.serviceRegistry = serviceRegistry;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
public final class StrategyRegistrationProviderImpl implements StrategyRegistrationProvider {

@Override
@SuppressWarnings("unchecked")
public Iterable<StrategyRegistration> getStrategyRegistrations() {
final SimpleStrategyRegistrationImpl<ConnectionProvider> c3p0 = new SimpleStrategyRegistrationImpl<>(
ConnectionProvider.class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -70,7 +71,7 @@ public boolean isUnwrappableAs(Class<?> unwrapType) {
}

@Override
@SuppressWarnings( {"unchecked"})
@SuppressWarnings("unchecked")
public <T> T unwrap(Class<T> unwrapType) {
if ( ConnectionProvider.class.equals( unwrapType )
|| DatasourceConnectionProviderImpl.class.isAssignableFrom( unwrapType ) ) {
Expand All @@ -88,26 +89,23 @@ else if ( DataSource.class.isAssignableFrom( unwrapType ) ) {
public void configure(Map<String, Object> 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 ) ) {
Expand Down
Loading
Loading