package org.hibernate.engine.jdbc.connections.internal;
import java.beans.BeanInfo;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.hibernate.HibernateException;
import org.hibernate.MultiTenancyStrategy;
import org.hibernate.boot.registry.StandardServiceInitiator;
import org.hibernate.boot.registry.selector.spi.StrategySelector;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.log.DeprecationLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.beans.BeanInfoHelper;
import org.hibernate.service.spi.ServiceRegistryImplementor;
public class ConnectionProviderInitiator implements StandardServiceInitiator<ConnectionProvider> {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( ConnectionProviderInitiator.class );
public static final ConnectionProviderInitiator INSTANCE = new ConnectionProviderInitiator();
public static final String C3P0_STRATEGY = "c3p0";
public static final String PROXOOL_STRATEGY = "proxool";
public static final String HIKARI_STRATEGY = "hikari";
public static final String VIBUR_STRATEGY = "vibur";
public static final String AGROAL_STRATEGY = "agroal";
public static final String INJECTION_DATA = "hibernate.connection_provider.injection_data";
private static final Map<String,String> LEGACY_CONNECTION_PROVIDER_MAPPING;
static {
LEGACY_CONNECTION_PROVIDER_MAPPING = new HashMap<String,String>( 5 );
LEGACY_CONNECTION_PROVIDER_MAPPING.put(
"org.hibernate.connection.DatasourceConnectionProvider",
DatasourceConnectionProviderImpl.class.getName()
);
LEGACY_CONNECTION_PROVIDER_MAPPING.put(
"org.hibernate.connection.DriverManagerConnectionProvider",
DriverManagerConnectionProviderImpl.class.getName()
);
LEGACY_CONNECTION_PROVIDER_MAPPING.put(
"org.hibernate.connection.UserSuppliedConnectionProvider",
UserSuppliedConnectionProviderImpl.class.getName()
);
}
@Override
public Class<ConnectionProvider> getServiceInitiated() {
return ConnectionProvider.class;
}
@Override
public ConnectionProvider initiateService(Map configurationValues, ServiceRegistryImplementor registry) {
final MultiTenancyStrategy strategy = MultiTenancyStrategy.determineMultiTenancyStrategy( configurationValues );
if ( strategy == MultiTenancyStrategy.DATABASE || strategy == MultiTenancyStrategy.SCHEMA ) {
return null;
}
final StrategySelector strategySelector = registry.getService( StrategySelector.class );
final Object explicitSetting = configurationValues.get( AvailableSettings.CONNECTION_PROVIDER );
if ( explicitSetting != null ) {
if ( explicitSetting instanceof ConnectionProvider ) {
return (ConnectionProvider) explicitSetting;
}
else if ( explicitSetting instanceof Class ) {
final Class providerClass = (Class) explicitSetting;
LOG.instantiatingExplicitConnectionProvider( providerClass.getName() );
return instantiateExplicitConnectionProvider( providerClass );
}
else {
String providerName = StringHelper.nullIfEmpty( explicitSetting.toString() );
if ( providerName != null ) {
if ( LEGACY_CONNECTION_PROVIDER_MAPPING.containsKey( providerName ) ) {
final String actualProviderName = LEGACY_CONNECTION_PROVIDER_MAPPING.get( providerName );
DeprecationLogger.DEPRECATION_LOGGER.connectionProviderClassDeprecated(
providerName,
actualProviderName
);
providerName = actualProviderName;
}
LOG.instantiatingExplicitConnectionProvider( providerName );
final Class providerClass = strategySelector.selectStrategyImplementor(
ConnectionProvider.class,
providerName
);
try {
return instantiateExplicitConnectionProvider( providerClass );
}
catch (Exception e) {
throw new HibernateException(
"Could not instantiate connection provider [" + providerName + "]",
e
);
}
}
}
}
if ( configurationValues.get( AvailableSettings.DATASOURCE ) != null ) {
return new DatasourceConnectionProviderImpl();
}
ConnectionProvider connectionProvider = null;
final Class<? extends ConnectionProvider> singleRegisteredProvider = getSingleRegisteredProvider( strategySelector );
if ( singleRegisteredProvider != null ) {
try {
connectionProvider = singleRegisteredProvider.newInstance();
}
catch (IllegalAccessException | InstantiationException e) {
throw new HibernateException( "Could not instantiate singular-registered ConnectionProvider", e );
}
}
if ( connectionProvider == null ) {
if ( c3p0ConfigDefined( configurationValues ) ) {
connectionProvider = instantiateC3p0Provider( strategySelector );
}
}
if ( connectionProvider == null ) {
if ( proxoolConfigDefined( configurationValues ) ) {
connectionProvider = instantiateProxoolProvider( strategySelector );
}
}
if ( connectionProvider == null ) {
if ( hikariConfigDefined( configurationValues ) ) {
connectionProvider = instantiateHikariProvider( strategySelector );
}
}
if ( connectionProvider == null ) {
if ( viburConfigDefined( configurationValues ) ) {
connectionProvider = instantiateViburProvider( strategySelector );
}
}
if ( connectionProvider == null ) {
if ( agroalConfigDefined( configurationValues ) ) {
connectionProvider = instantiateAgroalProvider( strategySelector );
}
}
if ( connectionProvider == null ) {
if ( configurationValues.get( AvailableSettings.URL ) != null ) {
connectionProvider = new DriverManagerConnectionProviderImpl();
}
}
if ( connectionProvider == null ) {
LOG.noAppropriateConnectionProvider();
connectionProvider = new UserSuppliedConnectionProviderImpl();
}
final Map injectionData = (Map) configurationValues.get( INJECTION_DATA );
if ( injectionData != null && injectionData.size() > 0 ) {
final ConnectionProvider theConnectionProvider = connectionProvider;
new BeanInfoHelper( connectionProvider.getClass() ).applyToBeanInfo(
connectionProvider,
new BeanInfoHelper.BeanInfoDelegate() {
public void processBeanInfo(BeanInfo beanInfo) throws Exception {
final PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
for ( PropertyDescriptor descriptor : descriptors ) {
final String propertyName = descriptor.getName();
if ( injectionData.containsKey( propertyName ) ) {
final Method method = descriptor.getWriteMethod();
method.invoke(
theConnectionProvider,
injectionData.get( propertyName )
);
}
}
}
}
);
}
return connectionProvider;
}
private Class<? extends ConnectionProvider> getSingleRegisteredProvider(StrategySelector strategySelector) {
final Collection<Class<? extends ConnectionProvider>> implementors = strategySelector.getRegisteredStrategyImplementors( ConnectionProvider.class );
if ( implementors != null && implementors.size() == 1 ) {
return implementors.iterator().next();
}
return null;
}
private ConnectionProvider instantiateExplicitConnectionProvider(Class providerClass) {
try {
return (ConnectionProvider) providerClass.newInstance();
}
catch (Exception e) {
throw new HibernateException( "Could not instantiate connection provider [" + providerClass.getName() + "]", e );
}
}
private static boolean c3p0ConfigDefined(Map configValues) {
for ( Object key : configValues.keySet() ) {
if ( String.class.isInstance( key )
&& ( (String) key ).startsWith( AvailableSettings.C3P0_CONFIG_PREFIX ) ) {
return true;
}
}
return false;
}
private ConnectionProvider instantiateC3p0Provider(StrategySelector strategySelector) {
try {
return strategySelector.selectStrategyImplementor( ConnectionProvider.class, C3P0_STRATEGY ).newInstance();
}
catch ( Exception e ) {
LOG.c3p0ProviderClassNotFound( C3P0_STRATEGY );
return null;
}
}
private static boolean proxoolConfigDefined(Map configValues) {
for ( Object key : configValues.keySet() ) {
if ( String.class.isInstance( key )
&& ( (String) key ).startsWith( AvailableSettings.PROXOOL_CONFIG_PREFIX ) ) {
return true;
}
}
return false;
}
private ConnectionProvider instantiateProxoolProvider(StrategySelector strategySelector) {
try {
return strategySelector.selectStrategyImplementor( ConnectionProvider.class, PROXOOL_STRATEGY ).newInstance();
}
catch ( Exception e ) {
LOG.proxoolProviderClassNotFound( PROXOOL_STRATEGY );
return null;
}
}
private boolean hikariConfigDefined(Map configValues) {
for ( Object key : configValues.keySet() ) {
if ( !String.class.isInstance( key ) ) {
continue;
}
if ( ( (String) key ).startsWith( "hibernate.hikari." ) ) {
return true;
}
}
return false;
}
private ConnectionProvider instantiateHikariProvider(StrategySelector strategySelector) {
try {
return strategySelector.selectStrategyImplementor( ConnectionProvider.class, HIKARI_STRATEGY ).newInstance();
}
catch ( Exception e ) {
LOG.hikariProviderClassNotFound();
return null;
}
}
private boolean viburConfigDefined(Map configValues) {
for ( Object key : configValues.keySet() ) {
if ( !String.class.isInstance( key ) ) {
continue;
}
if ( ( (String) key ).startsWith( "hibernate.vibur." ) ) {
return true;
}
}
return false;
}
private boolean agroalConfigDefined(Map configValues) {
for ( Object key : configValues.keySet() ) {
if ( !String.class.isInstance( key ) ) {
continue;
}
if ( ( (String) key ).startsWith( "hibernate.agroal." ) ) {
return true;
}
}
return false;
}
private ConnectionProvider instantiateViburProvider(StrategySelector strategySelector) {
try {
return strategySelector.selectStrategyImplementor( ConnectionProvider.class, VIBUR_STRATEGY ).newInstance();
}
catch ( Exception e ) {
LOG.viburProviderClassNotFound();
return null;
}
}
private ConnectionProvider instantiateAgroalProvider(StrategySelector strategySelector) {
try {
return strategySelector.selectStrategyImplementor( ConnectionProvider.class, AGROAL_STRATEGY ).newInstance();
}
catch ( Exception e ) {
LOG.agroalProviderClassNotFound();
return null;
}
}
public static Properties getConnectionProperties(Map<?,?> properties) {
final Properties result = new Properties();
for ( Map.Entry entry : properties.entrySet() ) {
if ( ! ( String.class.isInstance( entry.getKey() ) ) || ! String.class.isInstance( entry.getValue() ) ) {
continue;
}
final String key = (String) entry.getKey();
final String value = (String) entry.getValue();
if ( key.startsWith( AvailableSettings.CONNECTION_PREFIX ) ) {
if ( SPECIAL_PROPERTIES.contains( key ) ) {
if ( AvailableSettings.USER.equals( key ) ) {
result.setProperty( "user", value );
}
}
else {
result.setProperty(
key.substring( AvailableSettings.CONNECTION_PREFIX.length() + 1 ),
value
);
}
}
else if ( CONDITIONAL_PROPERTIES.containsKey( key ) ) {
result.setProperty( CONDITIONAL_PROPERTIES.get( key ), value );
}
}
return result;
}
private static final Set<String> SPECIAL_PROPERTIES;
private static final Map<String,Integer> ISOLATION_VALUE_MAP;
private static final Map<Integer, String> ISOLATION_VALUE_CONSTANT_NAME_MAP;
private static final Map<Integer, String> ISOLATION_VALUE_NICE_NAME_MAP;
static {
SPECIAL_PROPERTIES = new HashSet<String>();
SPECIAL_PROPERTIES.add( AvailableSettings.DATASOURCE );
SPECIAL_PROPERTIES.add( AvailableSettings.URL );
SPECIAL_PROPERTIES.add( AvailableSettings.CONNECTION_PROVIDER );
SPECIAL_PROPERTIES.add( AvailableSettings.POOL_SIZE );
SPECIAL_PROPERTIES.add( AvailableSettings.ISOLATION );
SPECIAL_PROPERTIES.add( AvailableSettings.DRIVER );
SPECIAL_PROPERTIES.add( AvailableSettings.USER );
ISOLATION_VALUE_MAP = new ConcurrentHashMap<String, Integer>();
ISOLATION_VALUE_MAP.put( "TRANSACTION_NONE", Connection.TRANSACTION_NONE );
ISOLATION_VALUE_MAP.put( "NONE", Connection.TRANSACTION_NONE );
ISOLATION_VALUE_MAP.put( "TRANSACTION_READ_UNCOMMITTED", Connection.TRANSACTION_READ_UNCOMMITTED );
ISOLATION_VALUE_MAP.put( "READ_UNCOMMITTED", Connection.TRANSACTION_READ_UNCOMMITTED );
ISOLATION_VALUE_MAP.put( "TRANSACTION_READ_COMMITTED", Connection.TRANSACTION_READ_COMMITTED );
ISOLATION_VALUE_MAP.put( "READ_COMMITTED", Connection.TRANSACTION_READ_COMMITTED );
ISOLATION_VALUE_MAP.put( "TRANSACTION_REPEATABLE_READ", Connection.TRANSACTION_REPEATABLE_READ );
ISOLATION_VALUE_MAP.put( "REPEATABLE_READ", Connection.TRANSACTION_REPEATABLE_READ );
ISOLATION_VALUE_MAP.put( "TRANSACTION_SERIALIZABLE", Connection.TRANSACTION_SERIALIZABLE );
ISOLATION_VALUE_MAP.put( "SERIALIZABLE", Connection.TRANSACTION_SERIALIZABLE );
ISOLATION_VALUE_CONSTANT_NAME_MAP = new ConcurrentHashMap<Integer, String>();
ISOLATION_VALUE_CONSTANT_NAME_MAP.put( Connection.TRANSACTION_NONE, "TRANSACTION_NONE" );
ISOLATION_VALUE_CONSTANT_NAME_MAP.put( Connection.TRANSACTION_READ_UNCOMMITTED, "TRANSACTION_READ_UNCOMMITTED" );
ISOLATION_VALUE_CONSTANT_NAME_MAP.put( Connection.TRANSACTION_READ_COMMITTED, "TRANSACTION_READ_COMMITTED" );
ISOLATION_VALUE_CONSTANT_NAME_MAP.put( Connection.TRANSACTION_REPEATABLE_READ, "TRANSACTION_REPEATABLE_READ" );
ISOLATION_VALUE_CONSTANT_NAME_MAP.put( Connection.TRANSACTION_SERIALIZABLE, "TRANSACTION_SERIALIZABLE" );
ISOLATION_VALUE_NICE_NAME_MAP = new ConcurrentHashMap<Integer, String>();
ISOLATION_VALUE_NICE_NAME_MAP.put( Connection.TRANSACTION_NONE, "NONE" );
ISOLATION_VALUE_NICE_NAME_MAP.put( Connection.TRANSACTION_READ_UNCOMMITTED, "READ_UNCOMMITTED" );
ISOLATION_VALUE_NICE_NAME_MAP.put( Connection.TRANSACTION_READ_COMMITTED, "READ_COMMITTED" );
ISOLATION_VALUE_NICE_NAME_MAP.put( Connection.TRANSACTION_REPEATABLE_READ, "REPEATABLE_READ" );
ISOLATION_VALUE_NICE_NAME_MAP.put( Connection.TRANSACTION_SERIALIZABLE, "SERIALIZABLE" );
}
private static final Map<String, String> CONDITIONAL_PROPERTIES;
static {
CONDITIONAL_PROPERTIES = new HashMap<String, String>();
CONDITIONAL_PROPERTIES.put( AvailableSettings.ENABLE_SYNONYMS, "includeSynonyms" );
}
public static Integer (Map settings) {
return interpretIsolation( settings.get( AvailableSettings.ISOLATION ) );
}
public static Integer interpretIsolation(Object setting) {
if ( setting == null ) {
return null;
}
if ( Number.class.isInstance( setting ) ) {
return ( (Number) setting ).intValue();
}
final String settingAsString = setting.toString();
if ( StringHelper.isEmpty( settingAsString ) ) {
return null;
}
if ( ISOLATION_VALUE_MAP.containsKey( settingAsString ) ) {
return ISOLATION_VALUE_MAP.get( settingAsString );
}
try {
return Integer.valueOf( settingAsString );
}
catch (NumberFormatException ignore) {
}
throw new HibernateException( "Could not interpret transaction isolation setting [" + setting + "]" );
}
public static String toIsolationConnectionConstantName(Integer isolation) {
final String name = ISOLATION_VALUE_CONSTANT_NAME_MAP.get( isolation );
if ( name == null ) {
throw new HibernateException(
"Could not convert isolation value [" + isolation + "] to java.sql.Connection constant name"
);
}
return name;
}
public static String toIsolationNiceName(Integer isolation) {
String name = null;
if ( isolation != null ) {
name = ISOLATION_VALUE_NICE_NAME_MAP.get( isolation );
}
if ( name == null ) {
name = "<unknown>";
}
return name;
}
}