All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.c3p0.internal.C3P0ConnectionProvider Maven / Gradle / Ivy

The newest version!
/*
 * SPDX-License-Identifier: LGPL-2.1-or-later
 * Copyright Red Hat Inc. and Hibernate Authors
 */
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.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 static org.hibernate.c3p0.internal.C3P0MessageLogger.C3P0_MSG_LOGGER;
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.
 *
 * @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 + ".";

	//swaldman 2006-08-28: define c3p0-style configuration parameters for properties with
	//                     hibernate-specific overrides to detect and warn about conflicting
	//                     declarations
	private static final String C3P0_STYLE_MIN_POOL_SIZE = "c3p0.minPoolSize";
	private static final String C3P0_STYLE_MAX_POOL_SIZE = "c3p0.maxPoolSize";
	private static final String C3P0_STYLE_MAX_IDLE_TIME = "c3p0.maxIdleTime";
	private static final String C3P0_STYLE_MAX_STATEMENTS = "c3p0.maxStatements";
	private static final String C3P0_STYLE_ACQUIRE_INCREMENT = "c3p0.acquireIncrement";
	private static final String C3P0_STYLE_IDLE_CONNECTION_TEST_PERIOD = "c3p0.idleConnectionTestPeriod";

	//swaldman 2006-08-28: define c3p0-style configuration parameters for initialPoolSize, which
	//                     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 Integer isolation;
	private boolean autocommit;

	private Function dbInfoProducer;
	private ServiceRegistryImplementor serviceRegistry;

	@Override
	public Connection getConnection() throws SQLException {
		final Connection connection = ds.getConnection();
		if ( isolation != null && isolation != connection.getTransactionIsolation() ) {
			connection.setTransactionIsolation( isolation );
		}
		if ( connection.getAutoCommit() != autocommit ) {
			connection.setAutoCommit( autocommit );
		}
		return connection;
	}

	@Override
	public void closeConnection(Connection connection) throws SQLException {
		connection.close();
	}

	@Override
	public boolean isUnwrappableAs(Class unwrapType) {
		return ConnectionProvider.class.equals( unwrapType )
			|| C3P0ConnectionProvider.class.isAssignableFrom( unwrapType )
			|| DataSource.class.isAssignableFrom( unwrapType );
	}

	@Override
	@SuppressWarnings("unchecked")
	public  T unwrap(Class unwrapType) {
		if ( ConnectionProvider.class.equals( unwrapType )
				|| C3P0ConnectionProvider.class.isAssignableFrom( unwrapType ) ) {
			return (T) this;
		}
		else if ( DataSource.class.isAssignableFrom( unwrapType ) ) {
			return (T) ds;
		}
		else {
			throw new UnknownUnwrapTypeException( unwrapType );
		}
	}

	@Override
	public void configure(Map props) {
		ConnectionInfoLogger.INSTANCE.configureConnectionPool( "C3p0" );

		final String jdbcDriverClass = extractSetting(
				props,
				JdbcSettings.JAKARTA_JDBC_DRIVER,
				JdbcSettings.DRIVER,
				JdbcSettings.JPA_JDBC_DRIVER
		);
		final String jdbcUrl = extractSetting(
				props,
				JdbcSettings.JAKARTA_JDBC_URL,
				JdbcSettings.URL,
				JdbcSettings.JPA_JDBC_URL
		);

		final Properties connectionProps = ConnectionProviderInitiator.getConnectionProperties( props );

		autocommit = getBoolean( JdbcSettings.AUTOCOMMIT, props );

		if ( jdbcDriverClass == null ) {
			ConnectionInfoLogger.INSTANCE.jdbcDriverNotSpecified();
		}
		else {
			try {
				serviceRegistry.requireService( ClassLoaderService.class ).classForName( jdbcDriverClass );
			}
			catch (ClassLoadingException e) {
				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 ) );
				}
			}

			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 );

		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
		);
	}

	@Override
	public boolean supportsAggressiveRelease() {
		return false;
	}

	@Override
	public DatabaseConnectionInfo getDatabaseConnectionInfo(Dialect dialect) {
		return dbInfoProducer.apply( dialect );
	}

	private void setOverwriteProperty(
			String hibernateStyleKey,
			String c3p0StyleKey,
			Map hibp,
			Properties c3p,
			Integer value) {
		if ( value != null ) {
			final String peeledC3p0Key = c3p0StyleKey.substring( 5 );
			c3p.put( peeledC3p0Key, String.valueOf( value ).trim() );
			if ( hibp.containsKey( c3p0StyleKey ) ) {
				warnPropertyConflict( hibernateStyleKey, c3p0StyleKey );
			}
			final String longC3p0StyleKey = "hibernate." + c3p0StyleKey;
			if ( hibp.containsKey( longC3p0StyleKey ) ) {
				warnPropertyConflict( hibernateStyleKey, longC3p0StyleKey );
			}
		}
	}

	private void warnPropertyConflict(String hibernateStyle, String c3p0Style) {
		C3P0_MSG_LOGGER.bothHibernateAndC3p0StylesSet( hibernateStyle, c3p0Style );
	}

	@Override
	public void stop() {
		ConnectionInfoLogger.INSTANCE.cleaningUpConnectionPool( C3p0Settings.C3P0_CONFIG_PREFIX );
		try {
			DataSources.destroy( ds );
		}
		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;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy