Skip to content

Instantly share code, notes, and snippets.

@gbadner
Created December 23, 2013 20:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gbadner/8103843 to your computer and use it in GitHub Desktop.
Save gbadner/8103843 to your computer and use it in GitHub Desktop.
JdbcServicesImpl
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.engine.jdbc.internal;
import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.MultiTenancyStrategy;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.LobCreationContext;
import org.hibernate.engine.jdbc.LobCreator;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
import org.hibernate.engine.jdbc.cursor.internal.StandardRefCursorSupport;
import org.hibernate.engine.jdbc.dialect.spi.DatabaseMetaDataDialectResolutionInfoAdapter;
import org.hibernate.engine.jdbc.dialect.spi.DialectFactory;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfoSource;
import org.hibernate.service.jdbc.connections.spi.JdbcConnectionAccess;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.ResultSetWrapper;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
import org.hibernate.engine.jdbc.spi.TypeInfo;
import org.hibernate.exception.internal.SQLExceptionTypeDelegate;
import org.hibernate.exception.internal.SQLStateConversionDelegate;
import org.hibernate.exception.internal.StandardSQLExceptionConverter;
import org.hibernate.exception.spi.SQLExceptionConverter;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.service.jdbc.env.spi.ExtractedDatabaseMetaData;
import org.hibernate.service.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.service.spi.Configurable;
import org.hibernate.service.spi.ServiceRegistryAwareService;
import org.hibernate.service.spi.ServiceRegistryImplementor;
/**
* Standard implementation of the {@link JdbcServices} contract
*
* @author Steve Ebersole
*/
public class JdbcServicesImpl implements JdbcServices, ServiceRegistryAwareService, Configurable {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( JdbcServicesImpl.class );
private ServiceRegistryImplementor serviceRegistry;
private JdbcEnvironment jdbcEnvironment;
private ConnectionProvider connectionProvider;
private SqlStatementLogger sqlStatementLogger;
@Override
public void injectServices(ServiceRegistryImplementor serviceRegistry) {
this.serviceRegistry = serviceRegistry;
}
@Override
public void configure(Map configValues) {
<<<<<<< HEAD
final JdbcConnectionAccess jdbcConnectionAccess = buildJdbcConnectionAccess( configValues );
final DialectFactory dialectFactory = serviceRegistry.getService( DialectFactory.class );
Dialect dialect = null;
LobCreatorBuilder lobCreatorBuilder = null;
boolean metaSupportsRefCursors = false;
boolean metaSupportsNamedParams = false;
boolean metaSupportsScrollable = false;
boolean metaSupportsGetGeneratedKeys = false;
boolean metaSupportsBatchUpdates = false;
boolean metaReportsDDLCausesTxnCommit = false;
boolean metaReportsDDLInTxnSupported = true;
String extraKeywordsString = "";
int sqlStateType = -1;
boolean lobLocatorUpdateCopy = false;
String catalogName = null;
String schemaName = null;
final LinkedHashSet<TypeInfo> typeInfoSet = new LinkedHashSet<TypeInfo>();
// 'hibernate.temp.use_jdbc_metadata_defaults' is a temporary magic value.
// The need for it is intended to be alleviated with future development, thus it is
// not defined as an Environment constant...
//
// it is used to control whether we should consult the JDBC metadata to determine
// certain Settings default values; it is useful to *not* do this when the database
// may not be available (mainly in tools usage).
final boolean useJdbcMetadata = ConfigurationHelper.getBoolean( "hibernate.temp.use_jdbc_metadata_defaults", configValues, true );
if ( useJdbcMetadata ) {
try {
final Connection connection = jdbcConnectionAccess.obtainConnection();
try {
final DatabaseMetaData meta = connection.getMetaData();
if ( LOG.isDebugEnabled() ) {
LOG.debugf(
"Database ->\n"
+ " name : %s\n"
+ " version : %s\n"
+ " major : %s\n"
+ " minor : %s",
meta.getDatabaseProductName(),
meta.getDatabaseProductVersion(),
meta.getDatabaseMajorVersion(),
meta.getDatabaseMinorVersion()
);
LOG.debugf(
"Driver ->\n"
+ " name : %s\n"
+ " version : %s\n"
+ " major : %s\n"
+ " minor : %s",
meta.getDriverName(),
meta.getDriverVersion(),
meta.getDriverMajorVersion(),
meta.getDriverMinorVersion()
);
LOG.debugf( "JDBC version : %s.%s", meta.getJDBCMajorVersion(), meta.getJDBCMinorVersion() );
}
metaSupportsRefCursors = StandardRefCursorSupport.supportsRefCursors( meta );
metaSupportsNamedParams = meta.supportsNamedParameters();
metaSupportsScrollable = meta.supportsResultSetType( ResultSet.TYPE_SCROLL_INSENSITIVE );
metaSupportsBatchUpdates = meta.supportsBatchUpdates();
metaReportsDDLCausesTxnCommit = meta.dataDefinitionCausesTransactionCommit();
metaReportsDDLInTxnSupported = !meta.dataDefinitionIgnoredInTransactions();
metaSupportsGetGeneratedKeys = meta.supportsGetGeneratedKeys();
extraKeywordsString = meta.getSQLKeywords();
sqlStateType = meta.getSQLStateType();
lobLocatorUpdateCopy = meta.locatorsUpdateCopy();
typeInfoSet.addAll( TypeInfo.extractTypeInfo( meta ) );
dialect = dialectFactory.buildDialect(
configValues,
new DialectResolutionInfoSource() {
@Override
public DialectResolutionInfo getDialectResolutionInfo() {
try {
return new DatabaseMetaDataDialectResolutionInfoAdapter( connection.getMetaData() );
}
catch ( SQLException sqlException ) {
throw new HibernateException(
"Unable to access java.sql.DatabaseMetaData to determine appropriate Dialect to use",
sqlException
);
}
}
}
);
catalogName = connection.getCatalog();
final SchemaNameResolver schemaNameResolver = determineExplicitSchemaNameResolver( configValues );
if ( schemaNameResolver == null ) {
// todo : add dialect method
// schemaNameResolver = dialect.getSchemaNameResolver();
}
if ( schemaNameResolver != null ) {
schemaName = schemaNameResolver.resolveSchemaName( connection );
}
lobCreatorBuilder = new LobCreatorBuilder( configValues, connection );
}
catch ( SQLException sqle ) {
LOG.unableToObtainConnectionMetadata( sqle.getMessage() );
}
finally {
if ( connection != null ) {
jdbcConnectionAccess.releaseConnection( connection );
}
}
}
catch ( SQLException sqle ) {
LOG.unableToObtainConnectionToQueryMetadata( sqle.getMessage() );
dialect = dialectFactory.buildDialect( configValues, null );
}
catch ( UnsupportedOperationException uoe ) {
// user supplied JDBC connections
dialect = dialectFactory.buildDialect( configValues, null );
}
}
else {
dialect = dialectFactory.buildDialect( configValues, null );
}
=======
this.jdbcEnvironment = serviceRegistry.getService( JdbcEnvironment.class );
this.connectionProvider = serviceRegistry.getService( ConnectionProvider.class );
>>>>>>> HHH-7472 - Introduce a "schema management" service
final boolean showSQL = ConfigurationHelper.getBoolean( Environment.SHOW_SQL, configValues, false );
final boolean formatSQL = ConfigurationHelper.getBoolean( Environment.FORMAT_SQL, configValues, false );
this.sqlStatementLogger = new SqlStatementLogger( showSQL, formatSQL );
<<<<<<< HEAD
this.extractedMetaDataSupport = new ExtractedDatabaseMetaDataImpl(
metaSupportsRefCursors,
metaSupportsNamedParams,
metaSupportsScrollable,
metaSupportsGetGeneratedKeys,
metaSupportsBatchUpdates,
metaReportsDDLInTxnSupported,
metaReportsDDLCausesTxnCommit,
parseKeywords( extraKeywordsString ),
parseSQLStateType( sqlStateType ),
lobLocatorUpdateCopy,
schemaName,
catalogName,
typeInfoSet
);
SQLExceptionConverter sqlExceptionConverter = dialect.buildSQLExceptionConverter();
if ( sqlExceptionConverter == null ) {
final StandardSQLExceptionConverter converter = new StandardSQLExceptionConverter();
sqlExceptionConverter = converter;
converter.addDelegate( dialect.buildSQLExceptionConversionDelegate() );
converter.addDelegate( new SQLExceptionTypeDelegate( dialect ) );
// todo : vary this based on extractedMetaDataSupport.getSqlStateType()
converter.addDelegate( new SQLStateConversionDelegate( dialect ) );
}
this.sqlExceptionHelper = new SqlExceptionHelper( sqlExceptionConverter );
}
private JdbcConnectionAccess buildJdbcConnectionAccess(Map configValues) {
final MultiTenancyStrategy multiTenancyStrategy = MultiTenancyStrategy.determineMultiTenancyStrategy( configValues );
if ( MultiTenancyStrategy.NONE == multiTenancyStrategy ) {
connectionProvider = serviceRegistry.getService( ConnectionProvider.class );
return new ConnectionProviderJdbcConnectionAccess( connectionProvider );
}
else {
connectionProvider = null;
final MultiTenantConnectionProvider multiTenantConnectionProvider = serviceRegistry.getService( MultiTenantConnectionProvider.class );
return new MultiTenantConnectionProviderJdbcConnectionAccess( multiTenantConnectionProvider );
}
}
private static class ConnectionProviderJdbcConnectionAccess implements JdbcConnectionAccess {
private final ConnectionProvider connectionProvider;
public ConnectionProviderJdbcConnectionAccess(ConnectionProvider connectionProvider) {
this.connectionProvider = connectionProvider;
}
@Override
public Connection obtainConnection() throws SQLException {
return connectionProvider.getConnection();
}
@Override
public void releaseConnection(Connection connection) throws SQLException {
connectionProvider.closeConnection( connection );
}
@Override
public boolean supportsAggressiveRelease() {
return connectionProvider.supportsAggressiveRelease();
}
}
private static class MultiTenantConnectionProviderJdbcConnectionAccess implements JdbcConnectionAccess {
private final MultiTenantConnectionProvider connectionProvider;
public MultiTenantConnectionProviderJdbcConnectionAccess(MultiTenantConnectionProvider connectionProvider) {
this.connectionProvider = connectionProvider;
}
@Override
public Connection obtainConnection() throws SQLException {
return connectionProvider.getAnyConnection();
}
@Override
public void releaseConnection(Connection connection) throws SQLException {
connectionProvider.releaseAnyConnection( connection );
}
@Override
public boolean supportsAggressiveRelease() {
return connectionProvider.supportsAggressiveRelease();
}
}
/**
* A constant naming the setting used to identify the {@link SchemaNameResolver} to use
* <p/>
* TODO : add to Environment
*/
public static final String SCHEMA_NAME_RESOLVER = "hibernate.schema_name_resolver";
private SchemaNameResolver determineExplicitSchemaNameResolver(Map configValues) {
final Object setting = configValues.get( SCHEMA_NAME_RESOLVER );
if ( SchemaNameResolver.class.isInstance( setting ) ) {
return (SchemaNameResolver) setting;
}
final String resolverClassName = (String) setting;
if ( resolverClassName != null ) {
try {
final Class resolverClass = ReflectHelper.classForName( resolverClassName, getClass() );
return (SchemaNameResolver) ReflectHelper.getDefaultConstructor( resolverClass ).newInstance();
}
catch ( ClassNotFoundException e ) {
LOG.unableToLocateConfiguredSchemaNameResolver( resolverClassName, e.toString() );
}
catch ( InvocationTargetException e ) {
LOG.unableToInstantiateConfiguredSchemaNameResolver( resolverClassName, e.getTargetException().toString() );
}
catch ( Exception e ) {
LOG.unableToInstantiateConfiguredSchemaNameResolver( resolverClassName, e.toString() );
}
}
return null;
}
private Set<String> parseKeywords(String extraKeywordsString) {
final Set<String> keywordSet = new HashSet<String>();
keywordSet.addAll( Arrays.asList( extraKeywordsString.split( "," ) ) );
return keywordSet;
}
private ExtractedDatabaseMetaData.SQLStateType parseSQLStateType(int sqlStateType) {
switch ( sqlStateType ) {
case DatabaseMetaData.sqlStateSQL99 : {
return ExtractedDatabaseMetaData.SQLStateType.SQL99;
}
case DatabaseMetaData.sqlStateXOpen : {
return ExtractedDatabaseMetaData.SQLStateType.XOpen;
}
default : {
return ExtractedDatabaseMetaData.SQLStateType.UNKOWN;
}
}
}
private static class ExtractedDatabaseMetaDataImpl implements ExtractedDatabaseMetaData {
private final boolean supportsRefCursors;
private final boolean supportsNamedParameters;
private final boolean supportsScrollableResults;
private final boolean supportsGetGeneratedKeys;
private final boolean supportsBatchUpdates;
private final boolean supportsDataDefinitionInTransaction;
private final boolean doesDataDefinitionCauseTransactionCommit;
private final Set<String> extraKeywords;
private final SQLStateType sqlStateType;
private final boolean lobLocatorUpdateCopy;
private final String connectionSchemaName;
private final String connectionCatalogName;
private final LinkedHashSet<TypeInfo> typeInfoSet;
private ExtractedDatabaseMetaDataImpl(
boolean supportsRefCursors,
boolean supportsNamedParameters,
boolean supportsScrollableResults,
boolean supportsGetGeneratedKeys,
boolean supportsBatchUpdates,
boolean supportsDataDefinitionInTransaction,
boolean doesDataDefinitionCauseTransactionCommit,
Set<String> extraKeywords,
SQLStateType sqlStateType,
boolean lobLocatorUpdateCopy,
String connectionSchemaName,
String connectionCatalogName,
LinkedHashSet<TypeInfo> typeInfoSet) {
this.supportsRefCursors = supportsRefCursors;
this.supportsNamedParameters = supportsNamedParameters;
this.supportsScrollableResults = supportsScrollableResults;
this.supportsGetGeneratedKeys = supportsGetGeneratedKeys;
this.supportsBatchUpdates = supportsBatchUpdates;
this.supportsDataDefinitionInTransaction = supportsDataDefinitionInTransaction;
this.doesDataDefinitionCauseTransactionCommit = doesDataDefinitionCauseTransactionCommit;
this.extraKeywords = extraKeywords;
this.sqlStateType = sqlStateType;
this.lobLocatorUpdateCopy = lobLocatorUpdateCopy;
this.connectionSchemaName = connectionSchemaName;
this.connectionCatalogName = connectionCatalogName;
this.typeInfoSet = typeInfoSet;
}
@Override
public boolean supportsRefCursors() {
return supportsRefCursors;
}
@Override
public boolean supportsNamedParameters() {
return supportsNamedParameters;
}
@Override
public boolean supportsScrollableResults() {
return supportsScrollableResults;
}
@Override
public boolean supportsGetGeneratedKeys() {
return supportsGetGeneratedKeys;
}
@Override
public boolean supportsBatchUpdates() {
return supportsBatchUpdates;
}
@Override
public boolean supportsDataDefinitionInTransaction() {
return supportsDataDefinitionInTransaction;
}
@Override
public boolean doesDataDefinitionCauseTransactionCommit() {
return doesDataDefinitionCauseTransactionCommit;
}
@Override
public Set<String> getExtraKeywords() {
return extraKeywords;
}
@Override
public SQLStateType getSqlStateType() {
return sqlStateType;
}
@Override
public boolean doesLobLocatorUpdateCopy() {
return lobLocatorUpdateCopy;
}
@Override
public String getConnectionSchemaName() {
return connectionSchemaName;
}
@Override
public String getConnectionCatalogName() {
return connectionCatalogName;
}
@Override
public LinkedHashSet<TypeInfo> getTypeInfoSet() {
return typeInfoSet;
}
@Override
public TypeInfo getTypeInfoForJdbcCode(int jdbcTypeCode) {
for ( TypeInfo typeInfo : typeInfoSet ) {
if ( typeInfo.getJdbcTypeCode() == jdbcTypeCode ) {
return typeInfo;
}
}
return null;
}
=======
>>>>>>> HHH-7472 - Introduce a "schema management" service
}
@Override
public ConnectionProvider getConnectionProvider() {
return connectionProvider;
}
@Override
public SqlStatementLogger getSqlStatementLogger() {
return sqlStatementLogger;
}
@Override
public SqlExceptionHelper getSqlExceptionHelper() {
return jdbcEnvironment.getSqlExceptionHelper();
}
@Override
public Dialect getDialect() {
return jdbcEnvironment.getDialect();
}
@Override
public ExtractedDatabaseMetaData getExtractedMetaDataSupport() {
return jdbcEnvironment.getExtractedDatabaseMetaData();
}
@Override
public LobCreator getLobCreator(LobCreationContext lobCreationContext) {
return jdbcEnvironment.getLobCreatorBuilder().buildLobCreator( lobCreationContext );
}
@Override
public ResultSetWrapper getResultSetWrapper() {
return ResultSetWrapperImpl.INSTANCE;
}
@Override
public JdbcEnvironment getJdbcEnvironment() {
return jdbcEnvironment;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment