HHH-5638 HHH-5639 HHH-5640 : Import DialectFactory. DialectResolver, ConnectionProvider, and JDBC batching services

This commit is contained in:
Gail Badner 2010-10-11 11:51:23 -07:00
parent 1f5c6f9578
commit 0bfe7869e4
45 changed files with 4943 additions and 0 deletions

View File

@ -0,0 +1,188 @@
/*
* 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.batch.internal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.engine.jdbc.batch.spi.Batch;
import org.hibernate.engine.jdbc.batch.spi.BatchObserver;
import org.hibernate.service.jdbc.spi.JdbcServices;
import org.hibernate.service.jdbc.spi.LogicalConnectionImplementor;
import org.hibernate.engine.jdbc.proxy.ProxyBuilder;
/**
* Convenience base class for implementors of the Batch interface.
*
* @author Steve Ebersole
*/
public abstract class AbstractBatchImpl implements Batch {
private static final Logger log = LoggerFactory.getLogger( AbstractBatchImpl.class );
private Object key;
private LogicalConnectionImplementor logicalConnection;
private Connection connectionProxy;
private LinkedHashMap<String,PreparedStatement> statements = new LinkedHashMap<String,PreparedStatement>();
private LinkedHashSet<BatchObserver> observers = new LinkedHashSet<BatchObserver>();
protected AbstractBatchImpl(Object key, LogicalConnectionImplementor logicalConnection) {
this.key = key;
this.logicalConnection = logicalConnection;
this.connectionProxy = ProxyBuilder.buildConnection( logicalConnection );
}
/**
* Perform batch execution.
* <p/>
* This is called from the explicit {@link #execute() execution}, but may also be called from elsewhere
* depending on the exact implementation.
*/
protected abstract void doExecuteBatch();
/**
* Convenience access to the underlying JDBC services.
*
* @return The underlying JDBC services.
*/
protected JdbcServices getJdbcServices() {
return logicalConnection.getJdbcServices();
}
/**
* Access to the batch's map of statements (keyed by SQL statement string).
*
* @return This batch's statements.
*/
protected LinkedHashMap<String,PreparedStatement> getStatements() {
return statements;
}
/**
* {@inheritDoc}
*/
public final Object getKey() {
return key;
}
/**
* {@inheritDoc}
*/
public void addObserver(BatchObserver observer) {
observers.add( observer );
}
/**
* {@inheritDoc}
*/
public final PreparedStatement getBatchStatement(String sql, boolean callable) {
PreparedStatement statement = statements.get( sql );
if ( statement == null ) {
statement = buildBatchStatement( sql, callable );
statements.put( sql, statement );
}
else {
log.debug( "reusing batch statement" );
getJdbcServices().getSqlStatementLogger().logStatement( sql );
}
return statement;
}
private PreparedStatement buildBatchStatement(String sql, boolean callable) {
try {
if ( callable ) {
return connectionProxy.prepareCall( sql );
}
else {
return connectionProxy.prepareStatement( sql );
}
}
catch ( SQLException sqle ) {
log.error( "sqlexception escaped proxy", sqle );
throw getJdbcServices().getSqlExceptionHelper().convert( sqle, "could not prepare batch statement", sql );
}
}
/**
* {@inheritDoc}
*/
public final void execute() {
notifyObserversExplicitExecution();
if ( statements.isEmpty() ) {
return;
}
try {
try {
doExecuteBatch();
}
finally {
releaseStatements();
}
}
finally {
statements.clear();
}
}
private void releaseStatements() {
for ( PreparedStatement statement : getStatements().values() ) {
try {
statement.close();
}
catch ( SQLException e ) {
log.error( "unable to release batch statement..." );
log.error( "sqlexception escaped proxy", e );
}
}
getStatements().clear();
}
private void notifyObserversExplicitExecution() {
for ( BatchObserver observer : observers ) {
observer.batchExplicitlyExecuted();
}
}
/**
* Convenience method to notify registered observers of an implicit execution of this batch.
*/
protected void notifyObserversImplicitExecution() {
for ( BatchObserver observer : observers ) {
observer.batchImplicitlyExecuted();
}
}
public void release() {
if ( getStatements() != null && !getStatements().isEmpty() ) {
log.info( "On release of batch it still contained JDBC statements" );
}
releaseStatements();
observers.clear();
}
}

View File

@ -0,0 +1,60 @@
/*
* 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.batch.internal;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.engine.jdbc.batch.spi.Batch;
import org.hibernate.service.jdbc.spi.LogicalConnectionImplementor;
/**
* A builder for {@link Batch} instances.
*
* @author Steve Ebersole
*/
public class BatchBuilder {
private static final Logger log = LoggerFactory.getLogger( BatchBuilder.class );
private int size;
public BatchBuilder() {
}
public BatchBuilder(int size) {
this.size = size;
}
public void setSize(int size) {
this.size = size;
}
public Batch buildBatch(Object key, LogicalConnectionImplementor logicalConnection) {
log.trace( "building batch [size={}]", size );
return size > 1
? new BatchingBatch( key, logicalConnection, size )
: new NonBatchingBatch( key, logicalConnection );
}
}

View File

@ -0,0 +1,125 @@
/*
* 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.batch.internal;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.HibernateException;
import org.hibernate.service.jdbc.spi.LogicalConnectionImplementor;
import org.hibernate.jdbc.Expectation;
/**
* A {@link org.hibernate.engine.jdbc.batch.spi.Batch} implementation which does batching based on a given size. Once the batch size is exceeded, the
* batch is implicitly executed.
*
* @author Steve Ebersole
*/
public class BatchingBatch extends AbstractBatchImpl {
private static final Logger log = LoggerFactory.getLogger( BatchingBatch.class );
private final int batchSize;
private Expectation[] expectations;
private int batchPosition;
public BatchingBatch(Object key, LogicalConnectionImplementor logicalConnection, int batchSize) {
super( key, logicalConnection );
this.batchSize = batchSize;
this.expectations = new Expectation[ batchSize ];
}
/**
* {@inheritDoc}
*/
public void addToBatch(Expectation expectation) {
if ( !expectation.canBeBatched() ) {
throw new HibernateException( "attempting to batch an operation which cannot be batched" );
}
for ( Map.Entry<String,PreparedStatement> entry : getStatements().entrySet() ) {
try {
entry.getValue().addBatch();
}
catch ( SQLException e ) {
log.error( "sqlexception escaped proxy", e );
throw getJdbcServices().getSqlExceptionHelper().convert( e, "could not perform addBatch", entry.getKey() );
}
}
expectations[ batchPosition++ ] = expectation;
if ( batchPosition == batchSize ) {
notifyObserversImplicitExecution();
doExecuteBatch();
}
}
/**
* {@inheritDoc}
*/
protected void doExecuteBatch() {
if ( batchPosition == 0 ) {
log.debug( "no batched statements to execute" );
}
else {
if ( log.isDebugEnabled() ) {
log.debug( "Executing batch size: " + batchPosition );
}
try {
for ( Map.Entry<String,PreparedStatement> entry : getStatements().entrySet() ) {
try {
final PreparedStatement statement = entry.getValue();
checkRowCounts( statement.executeBatch(), statement );
}
catch ( SQLException e ) {
log.error( "sqlexception escaped proxy", e );
throw getJdbcServices().getSqlExceptionHelper()
.convert( e, "could not perform addBatch", entry.getKey() );
}
}
}
catch ( RuntimeException re ) {
log.error( "Exception executing batch [{}]", re.getMessage() );
throw re;
}
finally {
batchPosition = 0;
}
}
}
private void checkRowCounts(int[] rowCounts, PreparedStatement ps) throws SQLException, HibernateException {
int numberOfRowCounts = rowCounts.length;
if ( numberOfRowCounts != batchPosition ) {
log.warn( "JDBC driver did not return the expected number of row counts" );
}
for ( int i = 0; i < numberOfRowCounts; i++ ) {
expectations[i].verifyOutcome( rowCounts[i], ps, i );
}
}
}

View File

@ -0,0 +1,67 @@
/*
* 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.batch.internal;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.service.jdbc.spi.LogicalConnectionImplementor;
import org.hibernate.jdbc.Expectation;
/**
* An implementation of {@link org.hibernate.engine.jdbc.batch.spi.Batch} which does not perform batching. It simply executes each statement as it is
* encountered.
*
* @author Steve Ebersole
*/
public class NonBatchingBatch extends AbstractBatchImpl {
private static final Logger log = LoggerFactory.getLogger( NonBatchingBatch.class );
protected NonBatchingBatch(Object key, LogicalConnectionImplementor logicalConnection) {
super( key, logicalConnection );
}
public void addToBatch(Expectation expectation) {
notifyObserversImplicitExecution();
for ( Map.Entry<String,PreparedStatement> entry : getStatements().entrySet() ) {
try {
final PreparedStatement statement = entry.getValue();
final int rowCount = statement.executeUpdate();
expectation.verifyOutcome( rowCount, statement, 0 );
}
catch ( SQLException e ) {
log.error( "sqlexception escaped proxy", e );
throw getJdbcServices().getSqlExceptionHelper().convert( e, "could not execute batch statement", entry.getKey() );
}
}
}
protected void doExecuteBatch() {
// nothing to do
}
}

View File

@ -0,0 +1,81 @@
/*
* 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.batch.spi;
import java.sql.PreparedStatement;
import org.hibernate.jdbc.Expectation;
/**
* Conceptually models a batch.
* <p/>
* Unlike directly in JDBC, here we add the ability to batch together multiple statements at a time. In the underlying
* JDBC this correlates to multiple {@link java.sql.PreparedStatement} objects (one for each DML string) maintained within the
* batch.
*
* @author Steve Ebersole
*/
public interface Batch {
/**
* Retrieves the object being used to key (uniquely identify) this batch.
*
* @return The batch key.
*/
public Object getKey();
/**
* Adds an observer to this batch.
*
* @param observer The batch observer.
*/
public void addObserver(BatchObserver observer);
/**
* Get a statement which is part of the batch, creating if necessary (and storing for next time).
*
* @param sql The SQL statement.
* @param callable Is the SQL statement callable?
* @return The prepared statement instance, representing the SQL statement.
*/
public PreparedStatement getBatchStatement(String sql, boolean callable);
/**
* Indicates completion of the current part of the batch.
*
* @param expectation The expectation for the part's result.
*/
public void addToBatch(Expectation expectation);
/**
* Execute this batch.
*/
public void execute();
/**
* Used to indicate that the batch instance is no longer needed and that, therefore, it can release its
* resources.
*/
public void release();
}

View File

@ -0,0 +1,41 @@
/*
* 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.batch.spi;
/**
* An observer contract for batch events.
*
* @author Steve Ebersole
*/
public interface BatchObserver {
/**
* Indicates explicit execution of the batch via a call to {@link Batch#execute()}.
*/
public void batchExplicitlyExecuted();
/**
* Indicates an implicit execution of the batch.
*/
public void batchImplicitlyExecuted();
}

View File

@ -0,0 +1,85 @@
/*
* 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.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import org.hibernate.HibernateException;
/**
* Basic support for building proxy handlers.
*
* @author Steve Ebersole
*/
public abstract class AbstractProxyHandler implements InvocationHandler {
private boolean valid = true;
private final int hashCode;
public AbstractProxyHandler(int hashCode) {
this.hashCode = hashCode;
}
protected abstract Object continueInvocation(Object proxy, Method method, Object[] args) throws Throwable;
public String toString() {
return super.toString() + "[valid=" + valid + "]";
}
public final int hashCode() {
return hashCode;
}
protected final boolean isValid() {
return valid;
}
protected final void invalidate() {
valid = false;
}
protected final void errorIfInvalid() {
if ( !isValid() ) {
throw new HibernateException( "proxy handle is no longer valid" );
}
}
public final Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
// basic Object methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( "toString".equals( methodName ) ) {
return this.toString();
}
if ( "hashCode".equals( methodName ) ) {
return this.hashCode();
}
if ( "equals".equals( methodName ) ) {
return this.equals( args[0] );
}
return continueInvocation( proxy, method, args );
}
}

View File

@ -0,0 +1,126 @@
/*
* 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.proxy;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.service.jdbc.spi.JdbcResourceRegistry;
import org.hibernate.service.jdbc.spi.JdbcServices;
/**
* Basic support for building {@link ResultSet}-based proxy handlers
*
* @author Steve Ebersole
*/
public abstract class AbstractResultSetProxyHandler extends AbstractProxyHandler {
private static final Logger log = LoggerFactory.getLogger( AbstractResultSetProxyHandler.class );
private ResultSet resultSet;
public AbstractResultSetProxyHandler(ResultSet resultSet) {
super( resultSet.hashCode() );
this.resultSet = resultSet;
}
protected abstract JdbcServices getJdbcServices();
protected abstract JdbcResourceRegistry getResourceRegistry();
protected abstract Statement getExposableStatement();
protected final ResultSet getResultSet() {
errorIfInvalid();
return resultSet;
}
protected final ResultSet getResultSetWithoutChecks() {
return resultSet;
}
protected Object continueInvocation(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
log.trace( "Handling invocation of ResultSet method [{}]", methodName );
// other methods allowed while invalid ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( "close".equals( methodName ) ) {
explicitClose( ( ResultSet ) proxy );
return null;
}
if ( "invalidate".equals( methodName ) ) {
invalidateHandle();
return null;
}
errorIfInvalid();
// handle the JDBC 4 Wrapper#isWrapperFor and Wrapper#unwrap calls
// these cause problems to the whole proxy scheme though as we need to return the raw objects
if ( "isWrapperFor".equals( methodName ) && args.length == 1 ) {
return method.invoke( getResultSetWithoutChecks(), args );
}
if ( "unwrap".equals( methodName ) && args.length == 1 ) {
return method.invoke( getResultSetWithoutChecks(), args );
}
if ( "getWrappedObject".equals( methodName ) ) {
return getResultSetWithoutChecks();
}
if ( "getStatement".equals( methodName ) ) {
return getExposableStatement();
}
try {
return method.invoke( resultSet, args );
}
catch ( InvocationTargetException e ) {
Throwable realException = e.getTargetException();
if ( SQLException.class.isInstance( realException ) ) {
throw getJdbcServices().getSqlExceptionHelper()
.convert( ( SQLException ) realException, realException.getMessage() );
}
else {
throw realException;
}
}
}
private void explicitClose(ResultSet proxy) {
if ( isValid() ) {
getResourceRegistry().release( proxy );
}
}
protected void invalidateHandle() {
resultSet = null;
invalidate();
}
}

View File

@ -0,0 +1,168 @@
/*
* 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.proxy;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.service.jdbc.spi.JdbcResourceRegistry;
import org.hibernate.service.jdbc.spi.JdbcServices;
import org.hibernate.service.jdbc.spi.LogicalConnectionImplementor;
/**
* Basic support for building {@link Statement}-based proxy handlers
*
* @author Steve Ebersole
*/
public abstract class AbstractStatementProxyHandler extends AbstractProxyHandler {
private static final Logger log = LoggerFactory.getLogger( AbstractStatementProxyHandler.class );
private ConnectionProxyHandler connectionProxyHandler;
private Connection connectionProxy;
private Statement statement;
protected AbstractStatementProxyHandler(
Statement statement,
ConnectionProxyHandler connectionProxyHandler,
Connection connectionProxy) {
super( statement.hashCode() );
this.statement = statement;
this.connectionProxyHandler = connectionProxyHandler;
this.connectionProxy = connectionProxy;
}
protected ConnectionProxyHandler getConnectionProxy() {
errorIfInvalid();
return connectionProxyHandler;
}
protected JdbcServices getJdbcServices() {
return getConnectionProxy().getJdbcServices();
}
protected JdbcResourceRegistry getResourceRegistry() {
return getConnectionProxy().getResourceRegistry();
}
protected Statement getStatement() {
errorIfInvalid();
return statement;
}
protected Statement getStatementWithoutChecks() {
return statement;
}
protected Object continueInvocation(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
log.trace( "Handling invocation of statement method [{}]", methodName );
// other methods allowed while invalid ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( "close".equals( methodName ) ) {
explicitClose( ( Statement ) proxy );
return null;
}
if ( "invalidate".equals( methodName ) ) {
invalidateHandle();
return null;
}
errorIfInvalid();
// handle the JDBC 4 Wrapper#isWrapperFor and Wrapper#unwrap calls
// these cause problems to the whole proxy scheme though as we need to return the raw objects
if ( "isWrapperFor".equals( methodName ) && args.length == 1 ) {
return method.invoke( getStatementWithoutChecks(), args );
}
if ( "unwrap".equals( methodName ) && args.length == 1 ) {
return method.invoke( getStatementWithoutChecks(), args );
}
if ( "getWrappedObject".equals( methodName ) ) {
return getStatementWithoutChecks();
}
if ( "getConnection".equals( methodName ) ) {
return connectionProxy;
}
beginningInvocationHandling( method, args );
try {
Object result = method.invoke( statement, args );
result = wrapIfNecessary( result, proxy, method );
return result;
}
catch ( InvocationTargetException e ) {
Throwable realException = e.getTargetException();
if ( SQLException.class.isInstance( realException ) ) {
throw connectionProxyHandler.getJdbcServices().getSqlExceptionHelper()
.convert( ( SQLException ) realException, realException.getMessage() );
}
else {
throw realException;
}
}
}
private Object wrapIfNecessary(Object result, Object proxy, Method method) {
if ( !( ResultSet.class.isAssignableFrom( method.getReturnType() ) ) ) {
return result;
}
final ResultSet wrapper;
if ( "getGeneratedKeys".equals( method.getName() ) ) {
wrapper = ProxyBuilder.buildImplicitResultSet( ( ResultSet ) result, connectionProxyHandler, connectionProxy );
}
else {
wrapper = ProxyBuilder.buildResultSet( ( ResultSet ) result, this, ( Statement ) proxy );
}
getResourceRegistry().register( wrapper );
return wrapper;
}
protected void beginningInvocationHandling(Method method, Object[] args) {
}
private void explicitClose(Statement proxy) {
if ( isValid() ) {
LogicalConnectionImplementor lc = getConnectionProxy().getLogicalConnection();
getResourceRegistry().release( proxy );
lc.afterStatementExecution();
}
}
private void invalidateHandle() {
connectionProxyHandler = null;
statement = null;
invalidate();
}
}

View File

@ -0,0 +1,56 @@
/*
* 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.proxy;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.Statement;
/**
* Invocation handler for {@link Statement} proxies
*
* @author Steve Ebersole
*/
public class BasicStatementProxyHandler extends AbstractStatementProxyHandler {
public BasicStatementProxyHandler(
Statement statement,
ConnectionProxyHandler connectionProxyHandler,
Connection connectionProxy) {
super( statement, connectionProxyHandler, connectionProxy );
}
protected void beginningInvocationHandling(Method method, Object[] args) {
if ( isExecution( method ) ) {
getJdbcServices().getSqlStatementLogger().logStatement( ( String ) args[0] );
}
}
private boolean isExecution(Method method) {
String methodName = method.getName();
return "execute".equals( methodName )
|| "executeQuery".equals( methodName )
|| "executeUpdate".equals( methodName );
}
}

View File

@ -0,0 +1,213 @@
/*
* 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.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.service.jdbc.spi.JdbcResourceRegistry;
import org.hibernate.service.jdbc.spi.JdbcServices;
import org.hibernate.service.jdbc.spi.ConnectionObserver;
import org.hibernate.service.jdbc.spi.LogicalConnectionImplementor;
/**
* The {@link InvocationHandler} for intercepting messages to {@link java.sql.Connection} proxies.
*
* @author Steve Ebersole
*/
public class ConnectionProxyHandler extends AbstractProxyHandler implements InvocationHandler, ConnectionObserver {
private static final Logger log = LoggerFactory.getLogger( ConnectionProxyHandler.class );
private LogicalConnectionImplementor logicalConnection;
public ConnectionProxyHandler(LogicalConnectionImplementor logicalConnection) {
super( logicalConnection.hashCode() );
this.logicalConnection = logicalConnection;
this.logicalConnection.addObserver( this );
}
/**
* Access to our logical connection.
*
* @return the logical connection
*/
protected LogicalConnectionImplementor getLogicalConnection() {
errorIfInvalid();
return logicalConnection;
}
/**
* Get reference to physical connection.
* <p/>
* NOTE : be sure this handler is still valid before calling!
*
* @return The physical connection
*/
private Connection extractPhysicalConnection() {
return logicalConnection.getConnection();
}
/**
* Provide access to JDBCServices.
* <p/>
* NOTE : package-protected
*
* @return JDBCServices
*/
JdbcServices getJdbcServices() {
return logicalConnection.getJdbcServices();
}
/**
* Provide access to JDBCContainer.
* <p/>
* NOTE : package-protected
*
* @return JDBCContainer
*/
JdbcResourceRegistry getResourceRegistry() {
return logicalConnection.getResourceRegistry();
}
protected Object continueInvocation(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
log.trace( "Handling invocation of connection method [{}]", methodName );
// other methods allowed while invalid ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( "close".equals( methodName ) ) {
explicitClose();
return null;
}
errorIfInvalid();
// handle the JDBC 4 Wrapper#isWrapperFor and Wrapper#unwrap calls
// these cause problems to the whole proxy scheme though as we need to return the raw objects
if ( "isWrapperFor".equals( methodName ) && args.length == 1 ) {
return method.invoke( extractPhysicalConnection(), args );
}
if ( "unwrap".equals( methodName ) && args.length == 1 ) {
return method.invoke( extractPhysicalConnection(), args );
}
if ( "getWrappedObject".equals( methodName ) ) {
return extractPhysicalConnection();
}
try {
Object result = method.invoke( extractPhysicalConnection(), args );
result = wrapIfNecessary( result, proxy, method, args );
return result;
}
catch( InvocationTargetException e ) {
Throwable realException = e.getTargetException();
if ( SQLException.class.isInstance( realException ) ) {
throw logicalConnection.getJdbcServices().getSqlExceptionHelper()
.convert( ( SQLException ) realException, realException.getMessage() );
}
else {
throw realException;
}
}
}
private Object wrapIfNecessary(Object result, Object proxy, Method method, Object[] args) {
String methodName = method.getName();
Object wrapped = result;
if ( "createStatement".equals( methodName ) ) {
wrapped = ProxyBuilder.buildStatement(
(Statement) result,
this,
( Connection ) proxy
);
getResourceRegistry().register( ( Statement ) wrapped );
}
else if ( "prepareStatement".equals( methodName ) ) {
wrapped = ProxyBuilder.buildPreparedStatement(
( String ) args[0],
(PreparedStatement) result,
this,
( Connection ) proxy
);
getResourceRegistry().register( ( Statement ) wrapped );
}
else if ( "prepareCall".equals( methodName ) ) {
wrapped = ProxyBuilder.buildCallableStatement(
( String ) args[0],
(CallableStatement) result,
this,
( Connection ) proxy
);
getResourceRegistry().register( ( Statement ) wrapped );
}
else if ( "getMetaData".equals( methodName ) ) {
wrapped = ProxyBuilder.buildDatabaseMetaData( (DatabaseMetaData) result, this, ( Connection ) proxy );
}
return wrapped;
}
private void explicitClose() {
if ( isValid() ) {
invalidateHandle();
}
}
private void invalidateHandle() {
log.trace( "Invalidating connection handle" );
logicalConnection = null;
invalidate();
}
/**
* {@inheritDoc}
*/
public void physicalConnectionObtained(Connection connection) {
}
/**
* {@inheritDoc}
*/
public void physicalConnectionReleased() {
log.info( "logical connection releasing its physical connection");
}
/**
* {@inheritDoc}
*/
public void logicalConnectionClosed() {
log.info( "*** logical connection closed ***" );
invalidateHandle();
}
}

View File

@ -0,0 +1,92 @@
/*
* 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.proxy;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* The InvocationHandler for intercepting messages to {@link java.sql.DatabaseMetaData} proxies.
* <p/>
* Mainly we need to intercept the methods defined on {@link java.sql.DatabaseMetaData} which expose
* {@link java.sql.ResultSet} instances, which in turn expose {@link java.sql.Statement}
* instances, which in turn...
*
* @author Steve Ebersole
*/
public class DatabaseMetaDataProxyHandler extends AbstractProxyHandler {
private ConnectionProxyHandler connectionProxyHandler;
private Connection connectionProxy;
private DatabaseMetaData databaseMetaData;
public DatabaseMetaDataProxyHandler(DatabaseMetaData databaseMetaData, ConnectionProxyHandler connectionProxyHandler, Connection connectionProxy) {
super( databaseMetaData.hashCode() );
this.connectionProxyHandler = connectionProxyHandler;
this.connectionProxy = connectionProxy;
this.databaseMetaData = databaseMetaData;
}
protected Object continueInvocation(Object proxy, Method method, Object[] args) throws Throwable {
// handle the JDBC 4 Wrapper#isWrapperFor and Wrapper#unwrap calls
// these cause problems to the whole proxy scheme though as we need to return the raw objects
if ( "isWrapperFor".equals( method.getName() ) && args.length == 1 ) {
return method.invoke( databaseMetaData, args );
}
if ( "unwrap".equals( method.getName() ) && args.length == 1 ) {
return method.invoke( databaseMetaData, args );
}
try {
boolean exposingResultSet = doesMethodExposeResultSet( method );
Object result = method.invoke( databaseMetaData, args );
if ( exposingResultSet ) {
result = ProxyBuilder.buildImplicitResultSet( (ResultSet) result, connectionProxyHandler, connectionProxy );
connectionProxyHandler.getResourceRegistry().register( ( ResultSet ) result );
}
return result;
}
catch ( InvocationTargetException e ) {
Throwable realException = e.getTargetException();
if ( SQLException.class.isInstance( realException ) ) {
throw connectionProxyHandler.getJdbcServices().getSqlExceptionHelper()
.convert( ( SQLException ) realException, realException.getMessage() );
}
else {
throw realException;
}
}
}
protected boolean doesMethodExposeResultSet(Method method) {
return ResultSet.class.isAssignableFrom( method.getReturnType() );
}
}

View File

@ -0,0 +1,81 @@
/*
* 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.proxy;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.hibernate.service.jdbc.spi.JdbcResourceRegistry;
import org.hibernate.service.jdbc.spi.JdbcServices;
/**
* Invocation handler for {@link java.sql.ResultSet} proxies obtained from other JDBC object proxies
*
* @author Steve Ebersole
*/
public class ImplicitResultSetProxyHandler extends AbstractResultSetProxyHandler {
private ConnectionProxyHandler connectionProxyHandler;
private Connection connectionProxy;
private Statement sourceStatement;
public ImplicitResultSetProxyHandler(ResultSet resultSet, ConnectionProxyHandler connectionProxyHandler, Connection connectionProxy) {
super( resultSet );
this.connectionProxyHandler = connectionProxyHandler;
this.connectionProxy = connectionProxy;
}
@Override
protected JdbcServices getJdbcServices() {
return connectionProxyHandler.getJdbcServices();
}
@Override
protected JdbcResourceRegistry getResourceRegistry() {
return connectionProxyHandler.getResourceRegistry();
}
@Override
protected Statement getExposableStatement() {
if ( sourceStatement == null ) {
try {
Statement stmnt = getResultSet().getStatement();
if ( stmnt == null ) {
return null;
}
sourceStatement = ProxyBuilder.buildImplicitStatement( stmnt, connectionProxyHandler, connectionProxy );
}
catch ( SQLException e ) {
throw getJdbcServices().getSqlExceptionHelper().convert( e, e.getMessage() );
}
}
return sourceStatement;
}
protected void invalidateHandle() {
sourceStatement = null;
super.invalidateHandle();
}
}

View File

@ -0,0 +1,48 @@
/*
* 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.proxy;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.Statement;
import org.hibernate.HibernateException;
/**
* Invocation handler for {@link java.sql.Statement} proxies obtained from other JDBC object proxies
*
* @author Steve Ebersole
*/
public class ImplicitStatementProxyHandler extends AbstractStatementProxyHandler {
protected ImplicitStatementProxyHandler(Statement statement, ConnectionProxyHandler connectionProxyHandler, Connection connectionProxy) {
super( statement, connectionProxyHandler, connectionProxy );
}
protected void beginningInvocationHandling(Method method, Object[] args) {
// disallow executions...
if ( method.getName().startsWith( "execute" ) ) {
throw new HibernateException( "execution not allowed on implicit statement object" );
}
}
}

View File

@ -0,0 +1,74 @@
/*
* 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.proxy;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.Statement;
/**
* Invocation handler for {@link java.sql.PreparedStatement} proxies
*
* @author Steve Ebersole
*/
public class PreparedStatementProxyHandler extends AbstractStatementProxyHandler {
private final String sql;
protected PreparedStatementProxyHandler(
String sql,
Statement statement,
ConnectionProxyHandler connectionProxyHandler,
Connection connectionProxy) {
super( statement, connectionProxyHandler, connectionProxy );
connectionProxyHandler.getJdbcServices().getSqlStatementLogger().logStatement( sql );
this.sql = sql;
}
protected void beginningInvocationHandling(Method method, Object[] args) {
if ( isExecution( method ) ) {
logExecution();
}
else {
journalPossibleParameterBind( method, args );
}
}
private void journalPossibleParameterBind(Method method, Object[] args) {
String methodName = method.getName();
// todo : is this enough???
if ( methodName.startsWith( "set" ) && args != null && args.length >= 2 ) {
journalParameterBind( method, args );
}
}
private void journalParameterBind(Method method, Object[] args) {
}
private boolean isExecution(Method method) {
return false;
}
private void logExecution() {
}
}

View File

@ -0,0 +1,208 @@
/*
* 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.proxy;
import java.lang.reflect.Proxy;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import org.hibernate.service.jdbc.spi.JdbcWrapper;
import org.hibernate.service.jdbc.spi.InvalidatableWrapper;
import org.hibernate.service.jdbc.spi.LogicalConnectionImplementor;
/**
* Centralized builder for proxy instances
*
* @author Steve Ebersole
*/
public class ProxyBuilder {
// Connection ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public static final Class[] CONNECTION_PROXY_INTERFACES = new Class[] {
Connection.class,
JdbcWrapper.class
};
public static Connection buildConnection(LogicalConnectionImplementor logicalConnection) {
ConnectionProxyHandler proxyHandler = new ConnectionProxyHandler( logicalConnection );
return ( Connection ) Proxy.newProxyInstance(
JdbcWrapper.class.getClassLoader(),
CONNECTION_PROXY_INTERFACES,
proxyHandler
);
}
// Statement ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public static final Class[] STMNT_PROXY_INTERFACES = new Class[] {
Statement.class,
JdbcWrapper.class,
InvalidatableWrapper.class
};
public static Statement buildStatement(
Statement statement,
ConnectionProxyHandler connectionProxyHandler,
Connection connectionProxy) {
BasicStatementProxyHandler proxyHandler = new BasicStatementProxyHandler(
statement,
connectionProxyHandler,
connectionProxy
);
return ( Statement ) Proxy.newProxyInstance(
JdbcWrapper.class.getClassLoader(),
STMNT_PROXY_INTERFACES,
proxyHandler
);
}
public static Statement buildImplicitStatement(
Statement statement,
ConnectionProxyHandler connectionProxyHandler,
Connection connectionProxy) {
if ( statement == null ) {
return null;
}
ImplicitStatementProxyHandler handler = new ImplicitStatementProxyHandler( statement, connectionProxyHandler, connectionProxy );
return ( Statement ) Proxy.newProxyInstance(
JdbcWrapper.class.getClassLoader(),
STMNT_PROXY_INTERFACES,
handler
);
}
// PreparedStatement ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public static final Class[] PREPARED_STMNT_PROXY_INTERFACES = new Class[] {
PreparedStatement.class,
JdbcWrapper.class,
InvalidatableWrapper.class
};
public static PreparedStatement buildPreparedStatement(
String sql,
Statement statement,
ConnectionProxyHandler connectionProxyHandler,
Connection connectionProxy) {
PreparedStatementProxyHandler proxyHandler = new PreparedStatementProxyHandler(
sql,
statement,
connectionProxyHandler,
connectionProxy
);
return ( PreparedStatement ) Proxy.newProxyInstance(
JdbcWrapper.class.getClassLoader(),
PREPARED_STMNT_PROXY_INTERFACES,
proxyHandler
);
}
// CallableStatement ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public static final Class[] CALLABLE_STMNT_PROXY_INTERFACES = new Class[] {
CallableStatement.class,
JdbcWrapper.class,
InvalidatableWrapper.class
};
public static CallableStatement buildCallableStatement(
String sql,
CallableStatement statement,
ConnectionProxyHandler connectionProxyHandler,
Connection connectionProxy) {
PreparedStatementProxyHandler proxyHandler = new PreparedStatementProxyHandler(
sql,
statement,
connectionProxyHandler,
connectionProxy
);
return ( CallableStatement ) Proxy.newProxyInstance(
JdbcWrapper.class.getClassLoader(),
CALLABLE_STMNT_PROXY_INTERFACES,
proxyHandler
);
}
// ResultSet ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public static final Class[] RESULTSET_PROXY_INTERFACES = new Class[] {
ResultSet.class,
JdbcWrapper.class,
InvalidatableWrapper.class
};
public static ResultSet buildResultSet(
ResultSet resultSet,
AbstractStatementProxyHandler statementProxyHandler,
Statement statementProxy) {
ResultSetProxyHandler proxyHandler = new ResultSetProxyHandler( resultSet, statementProxyHandler, statementProxy );
return ( ResultSet ) Proxy.newProxyInstance(
JdbcWrapper.class.getClassLoader(),
RESULTSET_PROXY_INTERFACES,
proxyHandler
);
}
public static ResultSet buildImplicitResultSet(
ResultSet resultSet,
ConnectionProxyHandler connectionProxyHandler,
Connection connectionProxy) {
ImplicitResultSetProxyHandler proxyHandler = new ImplicitResultSetProxyHandler( resultSet, connectionProxyHandler, connectionProxy );
return ( ResultSet ) Proxy.newProxyInstance(
JdbcWrapper.class.getClassLoader(),
RESULTSET_PROXY_INTERFACES,
proxyHandler
);
}
// DatabaseMetaData ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public static final Class[] METADATA_PROXY_INTERFACES = new Class[] {
DatabaseMetaData.class,
JdbcWrapper.class
};
public static DatabaseMetaData buildDatabaseMetaData(
DatabaseMetaData metaData,
ConnectionProxyHandler connectionProxyHandler,
Connection connectionProxy) {
DatabaseMetaDataProxyHandler handler = new DatabaseMetaDataProxyHandler( metaData, connectionProxyHandler, connectionProxy );
return ( DatabaseMetaData ) Proxy.newProxyInstance(
JdbcWrapper.class.getClassLoader(),
METADATA_PROXY_INTERFACES,
handler
);
}
}

View File

@ -0,0 +1,70 @@
/*
* 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.proxy;
import java.sql.ResultSet;
import java.sql.Statement;
import org.hibernate.service.jdbc.spi.JdbcResourceRegistry;
import org.hibernate.service.jdbc.spi.JdbcServices;
/**
* Invocation handler for {@link java.sql.ResultSet} proxies
*
* @author Steve Ebersole
*/
public class ResultSetProxyHandler extends AbstractResultSetProxyHandler {
private AbstractStatementProxyHandler statementProxyHandler;
private Statement statementProxy;
public ResultSetProxyHandler(
ResultSet resultSet,
AbstractStatementProxyHandler statementProxyHandler,
Statement statementProxy) {
super( resultSet );
this.statementProxyHandler = statementProxyHandler;
this.statementProxy = statementProxy;
}
protected AbstractStatementProxyHandler getStatementProxy() {
return statementProxyHandler;
}
protected Statement getExposableStatement() {
return statementProxy;
}
protected JdbcServices getJdbcServices() {
return getStatementProxy().getJdbcServices();
}
protected JdbcResourceRegistry getResourceRegistry() {
return getStatementProxy().getResourceRegistry();
}
protected void invalidateHandle() {
statementProxyHandler = null;
super.invalidateHandle();
}
}

View File

@ -0,0 +1,242 @@
/*
* 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.service.jdbc.connections.internal;
import java.beans.BeanInfo;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.HibernateException;
import org.hibernate.cfg.Environment;
import org.hibernate.service.classloading.spi.ClassLoaderService;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.internal.util.beans.BeanInfoHelper;
import org.hibernate.service.spi.ServicesRegistry;
import org.hibernate.service.spi.ServiceInitiator;
/**
* Instantiates and configures an appropriate {@link ConnectionProvider}.
*
* @author Gavin King
* @author Steve Ebersole
*/
public class ConnectionProviderInitiator implements ServiceInitiator<ConnectionProvider> {
public static final ConnectionProviderInitiator INSTANCE = new ConnectionProviderInitiator();
private static final Logger log = LoggerFactory.getLogger( ConnectionProviderInitiator.class );
public static final String C3P0_CONFIG_PREFIX = "hibernate.c3p0";
public static final String C3P0_PROVIDER_CLASS_NAME = "org.hibernate.connection.C3P0ConnectionProvider";
public static final String PROXOOL_CONFIG_PREFIX = "hibernate.proxool";
public static final String PROXOOL_PROVIDER_CLASS_NAME = "org.hibernate.connection.ProxoolConnectionProvider";
public static final String INJECTION_DATA = "hibernate.connection_provider.injection_data";
/**
* {@inheritDoc}
*/
public Class<ConnectionProvider> getServiceInitiated() {
return ConnectionProvider.class;
}
/**
* {@inheritDoc}
*/
public ConnectionProvider initiateService(Map configurationValues, ServicesRegistry registry) {
final ClassLoaderService classLoaderService = registry.getService( ClassLoaderService.class );
ConnectionProvider connectionProvider = null;
String providerClassName = (String) configurationValues.get( Environment.CONNECTION_PROVIDER );
if ( providerClassName != null ) {
connectionProvider = instantiateExplicitConnectionProvider( providerClassName, classLoaderService );
}
else if ( configurationValues.get( Environment.DATASOURCE ) != null ) {
connectionProvider = new DatasourceConnectionProviderImpl();
}
if ( connectionProvider == null ) {
if ( c3p0ConfigDefined( configurationValues ) && c3p0ProviderPresent( classLoaderService ) ) {
connectionProvider = instantiateExplicitConnectionProvider( C3P0_PROVIDER_CLASS_NAME,
classLoaderService
);
}
}
if ( connectionProvider == null ) {
if ( proxoolConfigDefined( configurationValues ) && proxoolProviderPresent( classLoaderService ) ) {
connectionProvider = instantiateExplicitConnectionProvider( PROXOOL_PROVIDER_CLASS_NAME,
classLoaderService
);
}
}
if ( connectionProvider == null ) {
if ( configurationValues.get( Environment.URL ) != null ) {
connectionProvider = new DriverManagerConnectionProviderImpl();
}
}
if ( connectionProvider == null ) {
log.warn( "No appropriate connection provider encountered, assuming application will be supplying connections" );
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 {
PropertyDescriptor[] descritors = beanInfo.getPropertyDescriptors();
for ( int i = 0, size = descritors.length; i < size; i++ ) {
String propertyName = descritors[i].getName();
if ( injectionData.containsKey( propertyName ) ) {
Method method = descritors[i].getWriteMethod();
method.invoke(
theConnectionProvider,
injectionData.get( propertyName )
);
}
}
}
}
);
}
return connectionProvider;
}
private ConnectionProvider instantiateExplicitConnectionProvider(
String providerClassName,
ClassLoaderService classLoaderService) {
try {
log.info( "Instantiating explicit connection provider: " + providerClassName );
return (ConnectionProvider) classLoaderService.classForName( providerClassName ).newInstance();
}
catch ( Exception e ) {
throw new HibernateException( "Could not instantiate connection provider [" + providerClassName + "]", e );
}
}
private boolean c3p0ProviderPresent(ClassLoaderService classLoaderService) {
try {
classLoaderService.classForName( C3P0_PROVIDER_CLASS_NAME );
}
catch ( Exception e ) {
log.warn(
"c3p0 properties were encountered, but the " + C3P0_PROVIDER_CLASS_NAME +
" provider class was not found on the classpath; these properties are going to be ignored."
);
return false;
}
return true;
}
private static boolean c3p0ConfigDefined(Map configValues) {
for ( Object key : configValues.keySet() ) {
if ( String.class.isInstance( key )
&& ( (String) key ).startsWith( C3P0_CONFIG_PREFIX ) ) {
return true;
}
}
return false;
}
private boolean proxoolProviderPresent(ClassLoaderService classLoaderService) {
try {
classLoaderService.classForName( PROXOOL_PROVIDER_CLASS_NAME );
}
catch ( Exception e ) {
log.warn(
"proxool properties were encountered, but the " + PROXOOL_PROVIDER_CLASS_NAME +
" provider class was not found on the classpath; these properties are going to be ignored."
);
return false;
}
return true;
}
private static boolean proxoolConfigDefined(Map configValues) {
for ( Object key : configValues.keySet() ) {
if ( String.class.isInstance( key )
&& ( (String) key ).startsWith( PROXOOL_CONFIG_PREFIX ) ) {
return true;
}
}
return false;
}
/**
* Transform JDBC connection properties.
*
* Passed in the form <tt>hibernate.connection.*</tt> to the
* format accepted by <tt>DriverManager</tt> by trimming the leading "<tt>hibernate.connection</tt>".
*/
public static Properties getConnectionProperties(Map<?,?> properties) {
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( Environment.CONNECTION_PREFIX ) ) {
if ( SPECIAL_PROPERTIES.contains( key ) ) {
if ( Environment.USER.equals( key ) ) {
result.setProperty( "user", value );
}
}
else {
final String passThruKey = key.substring( Environment.CONNECTION_PREFIX.length() + 1 );
result.setProperty( passThruKey, value );
}
}
}
return result;
}
private static final Set<String> SPECIAL_PROPERTIES;
static {
SPECIAL_PROPERTIES = new HashSet<String>();
SPECIAL_PROPERTIES.add( Environment.DATASOURCE );
SPECIAL_PROPERTIES.add( Environment.URL );
SPECIAL_PROPERTIES.add( Environment.CONNECTION_PROVIDER );
SPECIAL_PROPERTIES.add( Environment.POOL_SIZE );
SPECIAL_PROPERTIES.add( Environment.ISOLATION );
SPECIAL_PROPERTIES.add( Environment.DRIVER );
SPECIAL_PROPERTIES.add( Environment.USER );
}
}

View File

@ -0,0 +1,139 @@
/*
* 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.service.jdbc.connections.internal;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.HibernateException;
import org.hibernate.cfg.Environment;
import org.hibernate.service.jndi.spi.JndiService;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.spi.Configurable;
import org.hibernate.service.spi.InjectService;
import org.hibernate.service.spi.Stoppable;
/**
* A {@link ConnectionProvider} that manages connections from an underlying {@link DataSource}.
* <p/>
* The {@link DataSource} to use may be specified by either:<ul>
* <li>injection via {@link #setDataSource}</li>
* <li>decaring the {@link DataSource} instance using the {@link Environment#DATASOURCE} config property</li>
* <li>decaring the JNDI name under which the {@link DataSource} can be found via {@link Environment#DATASOURCE} config property</li>
* </ul>
*
* @author Gavin King
* @author Steve Ebersole
*/
public class DatasourceConnectionProviderImpl implements ConnectionProvider, Configurable, Stoppable {
private static final Logger log = LoggerFactory.getLogger( DatasourceConnectionProviderImpl.class );
private DataSource dataSource;
private String user;
private String pass;
private boolean useCredentials;
private JndiService jndiService;
private boolean available;
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
@InjectService( required = false )
public void setJndiService(JndiService jndiService) {
this.jndiService = jndiService;
}
/**
* {@inheritDoc}
*/
public void configure(Map configValues) {
if ( this.dataSource == null ) {
final Object dataSource = configValues.get( Environment.DATASOURCE );
if ( DataSource.class.isInstance( dataSource ) ) {
this.dataSource = (DataSource) dataSource;
}
else {
final String dataSourceJndiName = (String) dataSource;
if ( dataSourceJndiName == null ) {
throw new HibernateException(
"DataSource to use was not injected nor specified by [" + Environment.DATASOURCE
+ "] configuration property"
);
}
if ( jndiService == null ) {
throw new HibernateException( "Unable to locate JndiService to lookup Datasource" );
}
this.dataSource = (DataSource) jndiService.locate( dataSourceJndiName );
}
}
if ( this.dataSource == null ) {
throw new HibernateException( "Unable to determine appropriate DataSource to use" );
}
user = (String) configValues.get( Environment.USER );
pass = (String) configValues.get( Environment.PASS );
useCredentials = user != null || pass != null;
available = true;
}
public void stop() {
available = false;
dataSource = null;
}
/**
* {@inheritDoc}
*/
public Connection getConnection() throws SQLException {
if ( !available ) {
throw new HibernateException( "Provider is closed!" );
}
return useCredentials ? dataSource.getConnection( user, pass ) : dataSource.getConnection();
}
/**
* {@inheritDoc}
*/
public void closeConnection(Connection connection) throws SQLException {
connection.close();
}
/**
* {@inheritDoc}
*/
public boolean supportsAggressiveRelease() {
return true;
}
}

View File

@ -0,0 +1,196 @@
/*
* 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.service.jdbc.connections.internal;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Map;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.HibernateException;
import org.hibernate.cfg.Environment;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.spi.Configurable;
import org.hibernate.service.spi.Stoppable;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.util.ReflectHelper;
/**
* A connection provider that uses the {@link java.sql.DriverManager} directly to open connections and provides
* a very rudimentary connection pool.
* <p/>
* IMPL NOTE : not intended for production use!
*
* @author Gavin King
* @author Steve Ebersole
*/
public class DriverManagerConnectionProviderImpl implements ConnectionProvider, Configurable, Stoppable {
private static final Logger log = LoggerFactory.getLogger( DriverManagerConnectionProviderImpl.class );
private String url;
private Properties connectionProps;
private Integer isolation;
private int poolSize;
private boolean autocommit;
private final ArrayList<Connection> pool = new ArrayList<Connection>();
private int checkedOut = 0;
public void configure(Map configurationValues) {
log.info( "Using Hibernate built-in connection pool (not for production use!)" );
String driverClassName = (String) configurationValues.get( Environment.DRIVER );
if ( driverClassName == null ) {
log.warn( "no JDBC Driver class was specified by property " + Environment.DRIVER );
}
else {
try {
// trying via forName() first to be as close to DriverManager's semantics
Class.forName( driverClassName );
}
catch ( ClassNotFoundException cnfe ) {
try {
ReflectHelper.classForName( driverClassName );
}
catch ( ClassNotFoundException e ) {
throw new HibernateException( "Specified JDBC Driver " + driverClassName + " class not found", e );
}
}
}
poolSize = ConfigurationHelper.getInt( Environment.POOL_SIZE, configurationValues, 20 ); // default pool size 20
log.info( "Hibernate connection pool size: " + poolSize );
autocommit = ConfigurationHelper.getBoolean( Environment.AUTOCOMMIT, configurationValues );
log.info("autocommit mode: " + autocommit);
isolation = ConfigurationHelper.getInteger( Environment.ISOLATION, configurationValues );
if (isolation!=null)
log.info( "JDBC isolation level: " + Environment.isolationLevelToString( isolation.intValue() ) );
url = (String) configurationValues.get( Environment.URL );
if ( url == null ) {
String msg = "JDBC URL was not specified by property " + Environment.URL;
log.error( msg );
throw new HibernateException( msg );
}
connectionProps = ConnectionProviderInitiator.getConnectionProperties( configurationValues );
log.info( "using driver [" + driverClassName + "] at URL [" + url + "]" );
// if debug level is enabled, then log the password, otherwise mask it
if ( log.isDebugEnabled() ) {
log.info( "connection properties: " + connectionProps );
}
else if ( log.isInfoEnabled() ) {
log.info( "connection properties: " + ConfigurationHelper.maskOut( connectionProps, "password" ) );
}
}
public void stop() {
log.info( "cleaning up connection pool [" + url + "]" );
for ( Connection connection : pool ) {
try {
connection.close();
}
catch (SQLException sqle) {
log.warn( "problem closing pooled connection", sqle );
}
}
pool.clear();
}
public Connection getConnection() throws SQLException {
log.trace( "total checked-out connections: " + checkedOut );
// essentially, if we have available connections in the pool, use one...
synchronized (pool) {
if ( !pool.isEmpty() ) {
int last = pool.size() - 1;
if ( log.isTraceEnabled() ) {
log.trace( "using pooled JDBC connection, pool size: " + last );
checkedOut++;
}
Connection pooled = (Connection) pool.remove(last);
if ( isolation != null ) {
pooled.setTransactionIsolation( isolation.intValue() );
}
if ( pooled.getAutoCommit() != autocommit ) {
pooled.setAutoCommit( autocommit );
}
return pooled;
}
}
// otherwise we open a new connection...
log.debug( "opening new JDBC connection" );
Connection conn = DriverManager.getConnection( url, connectionProps );
if ( isolation != null ) {
conn.setTransactionIsolation( isolation.intValue() );
}
if ( conn.getAutoCommit() != autocommit ) {
conn.setAutoCommit(autocommit);
}
if ( log.isDebugEnabled() ) {
log.debug( "created connection to: " + url + ", Isolation Level: " + conn.getTransactionIsolation() );
}
checkedOut++;
return conn;
}
public void closeConnection(Connection conn) throws SQLException {
checkedOut--;
// add to the pool if the max size is not yet reached.
synchronized (pool) {
int currentSize = pool.size();
if ( currentSize < poolSize ) {
if ( log.isTraceEnabled() ) log.trace("returning connection to pool, pool size: " + (currentSize + 1) );
pool.add(conn);
return;
}
}
log.debug("closing JDBC connection");
conn.close();
}
protected void finalize() {
stop();
}
public boolean supportsAggressiveRelease() {
return false;
}
}

View File

@ -0,0 +1,60 @@
/*
* 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.service.jdbc.connections.internal;
import java.sql.Connection;
import java.sql.SQLException;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
/**
* An implementation of the {@link ConnectionProvider} interface that simply throws an exception when a connection
* is requested, the assumption being that the application is responsible for handing the connection to use to
* the session
*
* @author Gavin King
* @author Steve Ebersole
*/
public class UserSuppliedConnectionProviderImpl implements ConnectionProvider {
/**
* {@inheritDoc}
*/
public Connection getConnection() throws SQLException {
throw new UnsupportedOperationException( "The application must supply JDBC connections" );
}
/**
* {@inheritDoc}
*/
public void closeConnection(Connection conn) throws SQLException {
throw new UnsupportedOperationException( "The application must supply JDBC connections" );
}
/**
* {@inheritDoc}
*/
public boolean supportsAggressiveRelease() {
return false;
}
}

View File

@ -0,0 +1,78 @@
/*
* 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.service.jdbc.connections.spi;
import java.sql.Connection;
import java.sql.SQLException;
import org.hibernate.HibernateException;
import org.hibernate.service.spi.Service;
/**
* A contract for obtaining JDBC connections.
* <p/>
* Implementors might also implement connection pooling.
* <p/>
* Implementors should provide a public default constructor.
*
* @author Gavin King
* @author Steve Ebersole
*/
public interface ConnectionProvider extends Service {
/**
* Obtains a connection for Hibernate use according to the underlying strategy of this provider.
*
* @return The obtained JDBC connection
*
* @throws SQLException Indicates a problem opening a connection
* @throws HibernateException Inidcates a problem otherwise obtaining a connnection.
*/
public Connection getConnection() throws SQLException;
/**
* Release a connection from Hibernate use.
*
* @param conn The JDBC connection to release
*
* @throws SQLException Indicates a problem closing the connection
* @throws HibernateException Inidcates a problem otherwise releasing a connnection.
*/
public void closeConnection(Connection conn) throws SQLException;
/**
* Does this connection provider support aggressive release of JDBC
* connections and re-acquistion of those connections (if need be) later?
* <p/>
* This is used in conjunction with {@link org.hibernate.cfg.Environment.RELEASE_CONNECTIONS}
* to aggressively release JDBC connections. However, the configured ConnectionProvider
* must support re-acquisition of the same underlying connection for that semantic to work.
* <p/>
* Typically, this is only true in managed environments where a container
* tracks connections by transaction or thread.
*
* Note that JTA semantic depends on the fact that the underlying connection provider does
* support aggressive release.
*/
public boolean supportsAggressiveRelease();
}

View File

@ -0,0 +1,81 @@
/*
* 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.service.jdbc.dialect.internal;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.JDBCException;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.resolver.BasicSQLExceptionConverter;
import org.hibernate.service.jdbc.dialect.spi.DialectResolver;
import org.hibernate.exception.JDBCConnectionException;
/**
* A templated resolver impl which delegates to the {@link #resolveDialectInternal} method
* and handles any thrown {@link SQLException SQL errors}.
*
* @author Steve Ebersole
*/
public abstract class AbstractDialectResolver implements DialectResolver {
private static final Logger log = LoggerFactory.getLogger( AbstractDialectResolver.class );
/**
* {@inheritDoc}
* <p/>
* Here we template the resolution, delegating to {@link #resolveDialectInternal} and handling
* {@link java.sql.SQLException}s properly.
*/
public final Dialect resolveDialect(DatabaseMetaData metaData) {
try {
return resolveDialectInternal( metaData );
}
catch ( SQLException sqlException ) {
JDBCException jdbcException = BasicSQLExceptionConverter.INSTANCE.convert( sqlException );
if ( jdbcException instanceof JDBCConnectionException ) {
throw jdbcException;
}
else {
log.warn( BasicSQLExceptionConverter.MSG + " : " + sqlException.getMessage() );
return null;
}
}
catch ( Throwable t ) {
log.warn( "Error executing resolver [" + this + "] : " + t.getMessage() );
return null;
}
}
/**
* Perform the actual resolution without caring about handling {@link SQLException}s.
*
* @param metaData The database metadata
* @return The resolved dialect, or null if we could not resolve.
* @throws SQLException Indicates problems accessing the metadata.
*/
protected abstract Dialect resolveDialectInternal(DatabaseMetaData metaData) throws SQLException;
}

View File

@ -0,0 +1,123 @@
/*
* 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.service.jdbc.dialect.internal;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.Dialect;
import org.hibernate.service.classloading.spi.ClassLoaderService;
import org.hibernate.service.classloading.spi.ClassLoadingException;
import org.hibernate.service.jdbc.dialect.spi.DialectFactory;
import org.hibernate.service.jdbc.dialect.spi.DialectResolver;
import org.hibernate.service.spi.InjectService;
/**
* Standard implementation of the {@link DialectFactory} service.
*
* @author Steve Ebersole
*/
public class DialectFactoryImpl implements DialectFactory {
private ClassLoaderService classLoaderService;
@InjectService
public void setClassLoaderService(ClassLoaderService classLoaderService) {
this.classLoaderService = classLoaderService;
}
private DialectResolver dialectResolver;
@InjectService
public void setDialectResolver(DialectResolver dialectResolver) {
this.dialectResolver = dialectResolver;
}
/**
* {@inheritDoc}
*/
public Dialect buildDialect(Map configValues, Connection connection) throws HibernateException {
final String dialectName = (String) configValues.get( Environment.DIALECT );
if ( dialectName != null ) {
return constructDialect( dialectName );
}
else {
return determineDialect( connection );
}
}
private Dialect constructDialect(String dialectName) {
try {
return ( Dialect ) classLoaderService.classForName( dialectName ).newInstance();
}
catch ( ClassLoadingException cnfe ) {
throw new HibernateException( "Dialect class not found: " + dialectName, cnfe );
}
catch ( HibernateException e ) {
throw e;
}
catch ( Exception e ) {
throw new HibernateException( "Could not instantiate dialect class", e );
}
}
/**
* Determine the appropriate Dialect to use given the connection.
*
* @param connection The configured connection.
* @return The appropriate dialect instance.
*
* @throws HibernateException No connection given or no resolver could make
* the determination from the given connection.
*/
private Dialect determineDialect(Connection connection) {
if ( connection == null ) {
throw new HibernateException( "Connection cannot be null when 'hibernate.dialect' not set" );
}
try {
final DatabaseMetaData databaseMetaData = connection.getMetaData();
final Dialect dialect = dialectResolver.resolveDialect( databaseMetaData );
if ( dialect == null ) {
throw new HibernateException(
"Unable to determine Dialect to use [name=" + databaseMetaData.getDatabaseProductName() +
", majorVersion=" + databaseMetaData.getDatabaseMajorVersion() +
"]; user must register resolver or explicitly set 'hibernate.dialect'"
);
}
return dialect;
}
catch ( SQLException sqlException ) {
throw new HibernateException(
"Unable to access java.sql.DatabaseMetaData to determine appropriate Dialect to use",
sqlException
);
}
}
}

View File

@ -0,0 +1,53 @@
/*
* 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.service.jdbc.dialect.internal;
import java.util.Map;
import org.hibernate.service.jdbc.dialect.spi.DialectFactory;
import org.hibernate.service.spi.ServicesRegistry;
import org.hibernate.service.spi.ServiceInitiator;
/**
* Standard initiator for the standard {@link DialectFactory} service
*
* @author Steve Ebersole
*/
public class DialectFactoryInitiator implements ServiceInitiator<DialectFactory> {
public static final DialectFactoryInitiator INSTANCE = new DialectFactoryInitiator();
/**
* {@inheritDoc}
*/
public Class<DialectFactory> getServiceInitiated() {
return DialectFactory.class;
}
/**
* {@inheritDoc}
*/
public DialectFactory initiateService(Map configVales, ServicesRegistry registry) {
return new DialectFactoryImpl();
}
}

View File

@ -0,0 +1,53 @@
/*
* 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.service.jdbc.dialect.internal;
import java.util.Map;
import org.hibernate.service.jdbc.dialect.spi.DialectResolver;
import org.hibernate.service.spi.ServicesRegistry;
import org.hibernate.service.spi.ServiceInitiator;
/**
* Standard initiator for the standard {@link DialectResolver} service
*
* @author Steve Ebersole
*/
public class DialectResolverInitiator implements ServiceInitiator<DialectResolver> {
public static final DialectResolverInitiator INSTANCE = new DialectResolverInitiator();
/**
* {@inheritDoc}
*/
public Class<DialectResolver> getServiceInitiated() {
return DialectResolver.class;
}
/**
* {@inheritDoc}
*/
public DialectResolver initiateService(Map configVales, ServicesRegistry registry) {
return new StandardDialectResolver();
}
}

View File

@ -0,0 +1,98 @@
/*
* 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.service.jdbc.dialect.internal;
import java.sql.DatabaseMetaData;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.dialect.Dialect;
import org.hibernate.service.jdbc.dialect.spi.DialectResolver;
import org.hibernate.exception.JDBCConnectionException;
/**
* A {@link DialectResolver} implementation which coordinates resolution by delegating to sub-resolvers.
*
* @author Tomoto Shimizu Washio
* @author Steve Ebersole
*/
public class DialectResolverSet implements DialectResolver {
private static final Logger log = LoggerFactory.getLogger( DialectResolverSet.class );
private List<DialectResolver> resolvers;
public DialectResolverSet() {
this( new ArrayList<DialectResolver>() );
}
public DialectResolverSet(List<DialectResolver> resolvers) {
this.resolvers = resolvers;
}
public DialectResolverSet(DialectResolver... resolvers) {
this( Arrays.asList( resolvers ) );
}
public Dialect resolveDialect(DatabaseMetaData metaData) throws JDBCConnectionException {
for ( DialectResolver resolver : resolvers ) {
try {
Dialect dialect = resolver.resolveDialect( metaData );
if ( dialect != null ) {
return dialect;
}
}
catch ( JDBCConnectionException e ) {
throw e;
}
catch ( Exception e ) {
log.info( "sub-resolver threw unexpected exception, continuing to next : " + e.getMessage() );
}
}
return null;
}
/**
* Add a resolver at the end of the underlying resolver list. The resolver added by this method is at lower
* priority than any other existing resolvers.
*
* @param resolver The resolver to add.
*/
public void addResolver(DialectResolver resolver) {
resolvers.add( resolver );
}
/**
* Add a resolver at the beginning of the underlying resolver list. The resolver added by this method is at higher
* priority than any other existing resolvers.
*
* @param resolver The resolver to add.
*/
public void addResolverAtFirst(DialectResolver resolver) {
resolvers.add( 0, resolver );
}
}

View File

@ -0,0 +1,137 @@
/*
* 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.service.jdbc.dialect.internal;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.dialect.DerbyDialect;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.dialect.InformixDialect;
import org.hibernate.dialect.Ingres10Dialect;
import org.hibernate.dialect.Ingres9Dialect;
import org.hibernate.dialect.IngresDialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.Oracle10gDialect;
import org.hibernate.dialect.Oracle8iDialect;
import org.hibernate.dialect.Oracle9iDialect;
import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.dialect.SQLServerDialect;
import org.hibernate.dialect.SybaseASE15Dialect;
import org.hibernate.dialect.SybaseAnywhereDialect;
/**
* The standard Hibernate Dialect resolver.
*
* @author Steve Ebersole
*/
public class StandardDialectResolver extends AbstractDialectResolver {
private static final Logger log = LoggerFactory.getLogger( StandardDialectResolver.class );
protected Dialect resolveDialectInternal(DatabaseMetaData metaData) throws SQLException {
String databaseName = metaData.getDatabaseProductName();
int databaseMajorVersion = metaData.getDatabaseMajorVersion();
if ( "HSQL Database Engine".equals( databaseName ) ) {
return new HSQLDialect();
}
if ( "H2".equals( databaseName ) ) {
return new H2Dialect();
}
if ( "MySQL".equals( databaseName ) ) {
return new MySQLDialect();
}
if ( "PostgreSQL".equals( databaseName ) ) {
return new PostgreSQLDialect();
}
if ( "Apache Derby".equals( databaseName ) ) {
return new DerbyDialect();
}
if ( "ingres".equalsIgnoreCase( databaseName ) ) {
switch( databaseMajorVersion ) {
case 9:
int databaseMinorVersion = metaData.getDatabaseMinorVersion();
if (databaseMinorVersion > 2) {
return new Ingres9Dialect();
}
return new IngresDialect();
case 10:
log.warn( "Ingres " + databaseMajorVersion + " is not yet fully supported; using Ingres 9.3 dialect" );
return new Ingres10Dialect();
default:
log.warn( "Unknown Ingres major version [" + databaseMajorVersion + "] using Ingres 9.2 dialect" );
}
return new IngresDialect();
}
if ( databaseName.startsWith( "Microsoft SQL Server" ) ) {
return new SQLServerDialect();
}
if ( "Sybase SQL Server".equals( databaseName ) || "Adaptive Server Enterprise".equals( databaseName ) ) {
return new SybaseASE15Dialect();
}
if ( databaseName.startsWith( "Adaptive Server Anywhere" ) ) {
return new SybaseAnywhereDialect();
}
if ( "Informix Dynamic Server".equals( databaseName ) ) {
return new InformixDialect();
}
if ( databaseName.startsWith( "DB2/" ) ) {
return new DB2Dialect();
}
if ( "Oracle".equals( databaseName ) ) {
switch ( databaseMajorVersion ) {
case 11:
log.warn( "Oracle 11g is not yet fully supported; using 10g dialect" );
return new Oracle10gDialect();
case 10:
return new Oracle10gDialect();
case 9:
return new Oracle9iDialect();
case 8:
return new Oracle8iDialect();
default:
log.warn( "unknown Oracle major version [" + databaseMajorVersion + "]" );
}
}
return null;
}
}

View File

@ -0,0 +1,57 @@
/*
* 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.service.jdbc.dialect.spi;
import java.sql.Connection;
import java.util.Map;
import java.util.Properties;
import org.hibernate.HibernateException;
import org.hibernate.dialect.Dialect;
import org.hibernate.service.spi.Service;
/**
* A factory for generating Dialect instances.
*
* @author Steve Ebersole
*/
public interface DialectFactory extends Service {
/**
* Builds an appropriate Dialect instance.
* <p/>
* If a dialect is explicitly named in the incoming properties, it should used. Otherwise, it is
* determined by dialect resolvers based on the passed connection.
* <p/>
* An exception is thrown if a dialect was not explicitly set and no resolver could make
* the determination from the given connection.
*
* @param configValues The configuration properties.
* @param connection The configured connection.
*
* @return The appropriate dialect instance.
*
* @throws HibernateException No dialect specified and no resolver could make the determination.
*/
public Dialect buildDialect(Map configValues, Connection connection) throws HibernateException;
}

View File

@ -0,0 +1,53 @@
/*
* 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.service.jdbc.dialect.spi;
import java.sql.DatabaseMetaData;
import org.hibernate.dialect.Dialect;
import org.hibernate.exception.JDBCConnectionException;
import org.hibernate.service.spi.Service;
/**
* Contract for determining the {@link Dialect} to use based on a JDBC {@link java.sql.Connection}.
*
* @author Tomoto Shimizu Washio
* @author Steve Ebersole
*/
public interface DialectResolver extends Service {
/**
* Determine the {@link Dialect} to use based on the given JDBC {@link DatabaseMetaData}. Implementations are
* expected to return the {@link Dialect} instance to use, or null if the {@link DatabaseMetaData} does not match
* the criteria handled by this impl.
*
* @param metaData The JDBC metadata.
*
* @return The dialect to use, or null.
*
* @throws JDBCConnectionException Indicates a 'non transient connection problem', which indicates that
* we should stop resolution attempts.
*/
public Dialect resolveDialect(DatabaseMetaData metaData) throws JDBCConnectionException;
}

View File

@ -0,0 +1,218 @@
/*
* 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.service.jdbc.internal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.HibernateException;
import org.hibernate.service.jdbc.spi.SQLExceptionHelper;
import org.hibernate.service.jdbc.spi.JdbcResourceRegistry;
import org.hibernate.service.jdbc.spi.InvalidatableWrapper;
/**
* Standard implementation of the {@link org.hibernate.engine.jdbc.spi.JdbcResourceRegistry} contract
*
* @author Steve Ebersole
*/
public class JdbcResourceRegistryImpl implements JdbcResourceRegistry {
private static final Logger log = LoggerFactory.getLogger( JdbcResourceRegistryImpl.class );
private final HashMap<Statement,Set<ResultSet>> xref = new HashMap<Statement,Set<ResultSet>>();
private final Set<ResultSet> unassociatedResultSets = new HashSet<ResultSet>();
private final SQLExceptionHelper exceptionHelper;
public JdbcResourceRegistryImpl(SQLExceptionHelper exceptionHelper) {
this.exceptionHelper = exceptionHelper;
}
public void register(Statement statement) {
log.trace( "registering statement [" + statement + "]" );
if ( xref.containsKey( statement ) ) {
throw new HibernateException( "statement already registered with JDBCContainer" );
}
xref.put( statement, null );
}
public void release(Statement statement) {
log.trace( "releasing statement [" + statement + "]" );
Set<ResultSet> resultSets = xref.get( statement );
if ( resultSets != null ) {
for ( ResultSet resultSet : resultSets ) {
close( resultSet );
}
resultSets.clear();
}
xref.remove( statement );
close( statement );
}
public void register(ResultSet resultSet) {
log.trace( "registering result set [" + resultSet + "]" );
Statement statement;
try {
statement = resultSet.getStatement();
}
catch ( SQLException e ) {
throw exceptionHelper.convert( e, "unable to access statement from resultset" );
}
if ( statement != null ) {
if ( log.isWarnEnabled() && !xref.containsKey( statement ) ) {
log.warn( "resultset's statement was not yet registered" );
}
Set<ResultSet> resultSets = xref.get( statement );
if ( resultSets == null ) {
resultSets = new HashSet<ResultSet>();
xref.put( statement, resultSets );
}
resultSets.add( resultSet );
}
else {
unassociatedResultSets.add( resultSet );
}
}
public void release(ResultSet resultSet) {
log.trace( "releasing result set [{}]", resultSet );
Statement statement;
try {
statement = resultSet.getStatement();
}
catch ( SQLException e ) {
throw exceptionHelper.convert( e, "unable to access statement from resultset" );
}
if ( statement != null ) {
if ( log.isWarnEnabled() && !xref.containsKey( statement ) ) {
log.warn( "resultset's statement was not registered" );
}
Set<ResultSet> resultSets = xref.get( statement );
if ( resultSets != null ) {
resultSets.remove( resultSet );
if ( resultSets.isEmpty() ) {
xref.remove( statement );
}
}
}
else {
boolean removed = unassociatedResultSets.remove( resultSet );
if ( !removed ) {
log.warn( "ResultSet had no statement associated with it, but was not yet registered" );
}
}
close( resultSet );
}
public boolean hasRegisteredResources() {
return ! ( xref.isEmpty() && unassociatedResultSets.isEmpty() );
}
public void releaseResources() {
log.trace( "releasing JDBC container resources [{}]", this );
cleanup();
}
private void cleanup() {
for ( Map.Entry<Statement,Set<ResultSet>> entry : xref.entrySet() ) {
if ( entry.getValue() != null ) {
for ( ResultSet resultSet : entry.getValue() ) {
close( resultSet );
}
entry.getValue().clear();
}
close( entry.getKey() );
}
xref.clear();
for ( ResultSet resultSet : unassociatedResultSets ) {
close( resultSet );
}
unassociatedResultSets.clear();
}
public void close() {
log.trace( "closing JDBC container [{}]", this );
cleanup();
}
@SuppressWarnings({ "unchecked" })
protected void close(Statement statement) {
log.trace( "closing prepared statement [{}]", statement );
if ( statement instanceof InvalidatableWrapper ) {
InvalidatableWrapper<Statement> wrapper = ( InvalidatableWrapper<Statement> ) statement;
close( wrapper.getWrappedObject() );
wrapper.invalidate();
return;
}
try {
// if we are unable to "clean" the prepared statement,
// we do not close it
try {
if ( statement.getMaxRows() != 0 ) {
statement.setMaxRows( 0 );
}
if ( statement.getQueryTimeout() != 0 ) {
statement.setQueryTimeout( 0 );
}
}
catch( SQLException sqle ) {
// there was a problem "cleaning" the prepared statement
log.debug( "Exception clearing maxRows/queryTimeout [{}]", sqle.getMessage() );
return; // EARLY EXIT!!!
}
statement.close();
}
catch( SQLException sqle ) {
log.debug( "Unable to release statement [{}]", sqle.getMessage() );
}
}
@SuppressWarnings({ "unchecked" })
protected void close(ResultSet resultSet) {
log.trace( "closing result set [{}]", resultSet );
if ( resultSet instanceof InvalidatableWrapper ) {
InvalidatableWrapper<ResultSet> wrapper = (InvalidatableWrapper<ResultSet>) resultSet;
close( wrapper.getWrappedObject() );
wrapper.invalidate();
}
try {
resultSet.close();
}
catch( SQLException e ) {
log.debug( "Unable to release result set [{}]", e.getMessage() );
}
}
}

View File

@ -0,0 +1,339 @@
/*
* 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.service.jdbc.internal;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.Dialect;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.jdbc.dialect.spi.DialectFactory;
import org.hibernate.service.jdbc.spi.ExtractedDatabaseMetaData;
import org.hibernate.service.jdbc.spi.JdbcServices;
import org.hibernate.service.jdbc.spi.SQLExceptionHelper;
import org.hibernate.service.jdbc.spi.SQLStatementLogger;
import org.hibernate.service.jdbc.spi.SchemaNameResolver;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.internal.util.jdbc.TypeInfo;
import org.hibernate.service.spi.Configurable;
import org.hibernate.service.spi.InjectService;
import org.hibernate.util.ReflectHelper;
import org.hibernate.internal.util.jdbc.TypeInfoExtracter;
/**
* Standard implementation of the {@link JdbcServices} contract
*
* @author Steve Ebersole
*/
public class JdbcServicesImpl implements JdbcServices, Configurable {
private static final Logger log = LoggerFactory.getLogger( JdbcServicesImpl.class );
private ConnectionProvider connectionProvider;
@InjectService
public void setConnectionProvider(ConnectionProvider connectionProvider) {
this.connectionProvider = connectionProvider;
}
private DialectFactory dialectFactory;
@InjectService
public void setDialectFactory(DialectFactory dialectFactory) {
this.dialectFactory = dialectFactory;
}
private Dialect dialect;
private SQLStatementLogger sqlStatementLogger;
private SQLExceptionHelper sqlExceptionHelper;
private ExtractedDatabaseMetaData extractedMetaDataSupport;
public void configure(Map configValues) {
Dialect dialect = null;
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;
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).
boolean useJdbcMetadata = ConfigurationHelper.getBoolean( "hibernate.temp.use_jdbc_metadata_defaults", configValues, true );
if ( useJdbcMetadata ) {
try {
Connection conn = connectionProvider.getConnection();
try {
DatabaseMetaData meta = conn.getMetaData();
log.info( "Database ->\n" +
" name : " + meta.getDatabaseProductName() + '\n' +
" version : " + meta.getDatabaseProductVersion() + '\n' +
" major : " + meta.getDatabaseMajorVersion() + '\n' +
" minor : " + meta.getDatabaseMinorVersion()
);
log.info( "Driver ->\n" +
" name : " + meta.getDriverName() + '\n' +
" version : " + meta.getDriverVersion() + '\n' +
" major : " + meta.getDriverMajorVersion() + '\n' +
" minor : " + meta.getDriverMinorVersion()
);
log.info( "JDBC version : " + meta.getJDBCMajorVersion() + "." + meta.getJDBCMinorVersion() );
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( TypeInfoExtracter.extractTypeInfo( meta ) );
dialect = dialectFactory.buildDialect( configValues, conn );
catalogName = conn.getCatalog();
SchemaNameResolver schemaNameResolver = determineExplicitSchemaNameResolver( configValues );
if ( schemaNameResolver == null ) {
// todo : add dialect method
// schemaNameResolver = dialect.getSchemaNameResolver();
}
if ( schemaNameResolver != null ) {
schemaName = schemaNameResolver.resolveSchemaName( conn );
}
}
catch ( SQLException sqle ) {
log.warn( "Could not obtain connection metadata", sqle );
}
finally {
connectionProvider.closeConnection( conn );
}
}
catch ( SQLException sqle ) {
log.warn( "Could not obtain connection to query metadata", sqle );
dialect = dialectFactory.buildDialect( configValues, null );
}
catch ( UnsupportedOperationException uoe ) {
// user supplied JDBC connections
dialect = dialectFactory.buildDialect( configValues, null );
}
}
else {
dialect = dialectFactory.buildDialect( configValues, null );
}
final boolean showSQL = ConfigurationHelper.getBoolean( Environment.SHOW_SQL, configValues, false );
final boolean formatSQL = ConfigurationHelper.getBoolean( Environment.FORMAT_SQL, configValues, false );
this.dialect = dialect;
this.sqlStatementLogger = new SQLStatementLogger( showSQL, formatSQL );
this.sqlExceptionHelper = new SQLExceptionHelper( dialect.buildSQLExceptionConverter() );
this.extractedMetaDataSupport = new ExtractedDatabaseMetaDataImpl(
metaSupportsScrollable,
metaSupportsGetGeneratedKeys,
metaSupportsBatchUpdates,
metaReportsDDLInTxnSupported,
metaReportsDDLCausesTxnCommit,
parseKeywords( extraKeywordsString ),
parseSQLStateType( sqlStateType ),
lobLocatorUpdateCopy,
schemaName,
catalogName,
typeInfoSet
);
}
// todo : add to Environment
public static final String SCHEMA_NAME_RESOLVER = "hibernate.schema_name_resolver";
private SchemaNameResolver determineExplicitSchemaNameResolver(Map configValues) {
Object setting = configValues.get( SCHEMA_NAME_RESOLVER );
if ( SchemaNameResolver.class.isInstance( setting ) ) {
return (SchemaNameResolver) setting;
}
String resolverClassName = (String) setting;
if ( resolverClassName != null ) {
try {
Class resolverClass = ReflectHelper.classForName( resolverClassName, getClass() );
return (SchemaNameResolver) ReflectHelper.getDefaultConstructor( resolverClass ).newInstance();
}
catch ( ClassNotFoundException e ) {
log.warn( "Unable to locate configured schema name resolver class [" + resolverClassName + "]" + e.toString() );
}
catch ( InvocationTargetException e ) {
log.warn( "Unable to instantiate configured schema name resolver [" + resolverClassName + "]" + e.getTargetException().toString() );
}
catch ( Exception e ) {
log.warn( "Unable to instantiate configured schema name resolver [" + resolverClassName + "]" + e.toString() );
}
}
return null;
}
private Set<String> parseKeywords(String extraKeywordsString) {
Set<String> keywordSet = new HashSet<String>();
for ( String keyword : extraKeywordsString.split( "," ) ) {
keywordSet.add( keyword );
}
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 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 supportsScrollableResults,
boolean supportsGetGeneratedKeys,
boolean supportsBatchUpdates,
boolean supportsDataDefinitionInTransaction,
boolean doesDataDefinitionCauseTransactionCommit,
Set<String> extraKeywords,
SQLStateType sqlStateType,
boolean lobLocatorUpdateCopy,
String connectionSchemaName,
String connectionCatalogName,
LinkedHashSet<TypeInfo> typeInfoSet) {
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;
}
public boolean supportsScrollableResults() {
return supportsScrollableResults;
}
public boolean supportsGetGeneratedKeys() {
return supportsGetGeneratedKeys;
}
public boolean supportsBatchUpdates() {
return supportsBatchUpdates;
}
public boolean supportsDataDefinitionInTransaction() {
return supportsDataDefinitionInTransaction;
}
public boolean doesDataDefinitionCauseTransactionCommit() {
return doesDataDefinitionCauseTransactionCommit;
}
public Set<String> getExtraKeywords() {
return extraKeywords;
}
public SQLStateType getSqlStateType() {
return sqlStateType;
}
public boolean doesLobLocatorUpdateCopy() {
return lobLocatorUpdateCopy;
}
public String getConnectionSchemaName() {
return connectionSchemaName;
}
public String getConnectionCatalogName() {
return connectionCatalogName;
}
public LinkedHashSet<TypeInfo> getTypeInfoSet() {
return typeInfoSet;
}
}
public ConnectionProvider getConnectionProvider() {
return connectionProvider;
}
public SQLStatementLogger getSqlStatementLogger() {
return sqlStatementLogger;
}
public SQLExceptionHelper getSqlExceptionHelper() {
return sqlExceptionHelper;
}
public Dialect getDialect() {
return dialect;
}
public ExtractedDatabaseMetaData getExtractedMetaDataSupport() {
return extractedMetaDataSupport;
}
}

View File

@ -0,0 +1,53 @@
/*
* 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.service.jdbc.internal;
import java.util.Map;
import org.hibernate.service.jdbc.spi.JdbcServices;
import org.hibernate.service.spi.ServicesRegistry;
import org.hibernate.service.spi.ServiceInitiator;
/**
* Standard initiator for the standard {@link JdbcServices} service
*
* @author Steve Ebersole
*/
public class JdbcServicesInitiator implements ServiceInitiator<JdbcServices> {
public static final JdbcServicesInitiator INSTANCE = new JdbcServicesInitiator();
/**
* {@inheritDoc}
*/
public Class<JdbcServices> getServiceInitiated() {
return JdbcServices.class;
}
/**
* {@inheritDoc}
*/
public JdbcServices initiateService(Map configValues, ServicesRegistry registry) {
return new JdbcServicesImpl();
}
}

View File

@ -0,0 +1,250 @@
/*
* 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.service.jdbc.internal;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.HibernateException;
import org.hibernate.JDBCException;
import org.hibernate.service.jdbc.spi.JdbcResourceRegistry;
import org.hibernate.service.jdbc.spi.JdbcServices;
import org.hibernate.service.jdbc.spi.ConnectionObserver;
import org.hibernate.service.jdbc.spi.LogicalConnectionImplementor;
/**
* LogicalConnectionImpl implementation
*
* @author Steve Ebersole
*/
public class LogicalConnectionImpl implements LogicalConnectionImplementor {
private static final Logger log = LoggerFactory.getLogger( LogicalConnectionImpl.class );
private transient Connection physicalConnection;
private final ConnectionReleaseMode connectionReleaseMode;
private final JdbcServices jdbcServices;
private final JdbcResourceRegistry jdbcResourceRegistry;
private final List<ConnectionObserver> observers = new ArrayList<ConnectionObserver>();
private boolean releasesEnabled = true;
private final boolean isUserSuppliedConnection;
private boolean isClosed;
public LogicalConnectionImpl(
Connection userSuppliedConnection,
ConnectionReleaseMode connectionReleaseMode,
JdbcServices jdbcServices) {
if ( connectionReleaseMode == ConnectionReleaseMode.AFTER_STATEMENT &&
! jdbcServices.getConnectionProvider().supportsAggressiveRelease() ) {
log.debug( "connection provider reports to not support aggressive release; overriding" );
connectionReleaseMode = ConnectionReleaseMode.AFTER_TRANSACTION;
}
this.physicalConnection = userSuppliedConnection;
this.connectionReleaseMode = connectionReleaseMode;
this.jdbcServices = jdbcServices;
this.jdbcResourceRegistry = new JdbcResourceRegistryImpl( jdbcServices.getSqlExceptionHelper() );
this.isUserSuppliedConnection = ( userSuppliedConnection != null );
}
/**
* {@inheritDoc}
*/
public JdbcServices getJdbcServices() {
return jdbcServices;
}
/**
* {@inheritDoc}
*/
public JdbcResourceRegistry getResourceRegistry() {
return jdbcResourceRegistry;
}
/**
* {@inheritDoc}
*/
public void addObserver(ConnectionObserver observer) {
observers.add( observer );
}
/**
* {@inheritDoc}
*/
public boolean isOpen() {
return !isClosed;
}
/**
* {@inheritDoc}
*/
public boolean isPhysicallyConnected() {
return physicalConnection != null;
}
/**
* {@inheritDoc}
*/
public Connection getConnection() throws HibernateException {
if ( isClosed ) {
throw new HibernateException( "Logical connection is closed" );
}
if ( physicalConnection == null ) {
if ( isUserSuppliedConnection ) {
// should never happen
throw new HibernateException( "User-supplied connection was null" );
}
obtainConnection();
}
return physicalConnection;
}
/**
* {@inheritDoc}
*/
public Connection close() {
log.trace( "closing logical connection" );
Connection c = physicalConnection;
if ( !isUserSuppliedConnection && physicalConnection != null ) {
jdbcResourceRegistry.close();
releaseConnection();
}
// not matter what
physicalConnection = null;
isClosed = true;
for ( ConnectionObserver observer : observers ) {
observer.logicalConnectionClosed();
}
log.trace( "logical connection closed" );
return c;
}
/**
* {@inheritDoc}
*/
public ConnectionReleaseMode getConnectionReleaseMode() {
return connectionReleaseMode;
}
public void afterStatementExecution() {
log.trace( "starting after statement execution processing [{}]", connectionReleaseMode );
if ( connectionReleaseMode == ConnectionReleaseMode.AFTER_STATEMENT ) {
if ( ! releasesEnabled ) {
log.debug( "skipping aggressive release due to manual disabling" );
return;
}
if ( jdbcResourceRegistry.hasRegisteredResources() ) {
log.debug( "skipping aggressive release due to registered resources" );
return;
}
releaseConnection();
}
}
public void afterTransaction() {
if ( connectionReleaseMode == ConnectionReleaseMode.AFTER_STATEMENT ||
connectionReleaseMode == ConnectionReleaseMode.AFTER_TRANSACTION ) {
if ( jdbcResourceRegistry.hasRegisteredResources() ) {
log.info( "forcing container resource cleanup on transaction completion" );
jdbcResourceRegistry.releaseResources();
}
aggressiveRelease();
}
}
public void disableReleases() {
log.trace( "disabling releases" );
releasesEnabled = false;
}
public void enableReleases() {
log.trace( "(re)enabling releases" );
releasesEnabled = true;
afterStatementExecution();
}
/**
* Force aggresive release of the underlying connection.
*/
public void aggressiveRelease() {
if ( isUserSuppliedConnection ) {
log.debug( "cannot aggressively release user-supplied connection; skipping" );
}
else {
log.debug( "aggressively releasing JDBC connection" );
if ( physicalConnection != null ) {
releaseConnection();
}
}
}
/**
* Pysically opens a JDBC Connection.
*
* @throws org.hibernate.JDBCException Indicates problem opening a connection
*/
private void obtainConnection() throws JDBCException {
log.debug( "obtaining JDBC connection" );
try {
physicalConnection = getJdbcServices().getConnectionProvider().getConnection();
for ( ConnectionObserver observer : observers ) {
observer.physicalConnectionObtained( physicalConnection );
}
log.debug( "obtained JDBC connection" );
}
catch ( SQLException sqle) {
throw getJdbcServices().getSqlExceptionHelper().convert( sqle, "Could not open connection" );
}
}
/**
* Physically closes the JDBC Connection.
*
* @throws JDBCException Indicates problem closing a connection
*/
private void releaseConnection() throws JDBCException {
log.debug( "releasing JDBC connection" );
try {
if ( !physicalConnection.isClosed() ) {
getJdbcServices().getSqlExceptionHelper().logAndClearWarnings( physicalConnection );
}
for ( ConnectionObserver observer : observers ) {
observer.physicalConnectionReleased();
}
getJdbcServices().getConnectionProvider().closeConnection( physicalConnection );
physicalConnection = null;
log.debug( "released JDBC connection" );
}
catch (SQLException sqle) {
throw getJdbcServices().getSqlExceptionHelper().convert( sqle, "Could not close connection" );
}
}
}

View File

@ -0,0 +1,50 @@
/*
* 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.service.jdbc.spi;
import java.sql.Connection;
/**
* An observer of logical connection events.
*
* @author Steve Ebersole
*/
public interface ConnectionObserver {
/**
* A physical connection was obtained.
*
* @param connection The physical connection just obtained.
*/
public void physicalConnectionObtained(Connection connection);
/**
* A physical connection was released.
*/
public void physicalConnectionReleased();
/**
* The logical connection was closed.
*/
public void logicalConnectionClosed();
}

View File

@ -0,0 +1,133 @@
/*
* 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.service.jdbc.spi;
import java.util.LinkedHashSet;
import java.util.Set;
import org.hibernate.internal.util.jdbc.TypeInfo;
/**
* Information extracted from {@link java.sql.DatabaseMetaData} regarding what the JDBC driver reports as
* being supported or not. Obviously {@link java.sql.DatabaseMetaData} reports many things, these are a few in
* which we have particular interest.
*
* @author Steve Ebersole
*/
public interface ExtractedDatabaseMetaData {
public enum SQLStateType {
XOpen,
SQL99,
UNKOWN
}
/**
* Did the driver report to supporting scrollable result sets?
*
* @return True if the driver reported to support {@link java.sql.ResultSet#TYPE_SCROLL_INSENSITIVE}.
* @see java.sql.DatabaseMetaData#supportsResultSetType
*/
public boolean supportsScrollableResults();
/**
* Did the driver report to supporting retrieval of generated keys?
*
* @return True if the if the driver reported to support calls to {@link java.sql.Statement#getGeneratedKeys}
* @see java.sql.DatabaseMetaData#supportsGetGeneratedKeys
*/
public boolean supportsGetGeneratedKeys();
/**
* Did the driver report to supporting batched updates?
*
* @return True if the driver supports batched updates
* @see java.sql.DatabaseMetaData#supportsBatchUpdates
*/
public boolean supportsBatchUpdates();
/**
* Did the driver report to support performing DDL within transactions?
*
* @return True if the drivers supports DDL statements within transactions.
* @see java.sql.DatabaseMetaData#dataDefinitionIgnoredInTransactions
*/
public boolean supportsDataDefinitionInTransaction();
/**
* Did the driver report to DDL statements performed within a transaction performing an implicit commit of the
* transaction.
*
* @return True if the driver/database performs an implicit commit of transaction when DDL statement is
* performed
* @see java.sql.DatabaseMetaData#dataDefinitionCausesTransactionCommit()
*/
public boolean doesDataDefinitionCauseTransactionCommit();
/**
* Get the list of extra keywords (beyond standard SQL92 keywords) reported by the driver.
*
* @return The extra keywords used by this database.
* @see java.sql.DatabaseMetaData#getSQLKeywords()
*/
public Set<String> getExtraKeywords();
/**
* Retrieve the type of codes the driver says it uses for {@code SQLState}. They might follow either
* the X/Open standard or the SQL92 standard.
*
* @return The SQLState strategy reportedly used by this driver/database.
* @see java.sql.DatabaseMetaData#getSQLStateType()
*/
public SQLStateType getSqlStateType();
/**
* Did the driver report that updates to a LOB locator affect a copy of the LOB?
*
* @return True if updates to the state of a LOB locator update only a copy.
* @see java.sql.DatabaseMetaData#locatorsUpdateCopy()
*/
public boolean doesLobLocatorUpdateCopy();
/**
* Retrieve the name of the schema in effect when we connected to the database.
*
* @return The schema name
*/
public String getConnectionSchemaName();
/**
* Retrieve the name of the catalog in effect when we connected to the database.
*
* @return The catalog name
*/
public String getConnectionCatalogName();
/**
* Set of type info reported by the driver.
*
* @return
*/
public LinkedHashSet<TypeInfo> getTypeInfoSet();
}

View File

@ -0,0 +1,36 @@
/*
* 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.service.jdbc.spi;
/**
* Specialized {@link JdbcWrapper} contract for wrapped objects that can additioanlly be invalidated
*
* @author Steve Ebersole
*/
public interface InvalidatableWrapper<T> extends JdbcWrapper<T> {
/**
* Make the wrapper invalid for further usage.
*/
public void invalidate();
}

View File

@ -0,0 +1,81 @@
/*
* 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.service.jdbc.spi;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* Defines a registry of JDBC resources related to a particular unit of work.
*
* @author Steve Ebersole
*/
public interface JdbcResourceRegistry {
/**
* Register a JDBC statement.
*
* @param statement The statement to register.
*/
public void register(Statement statement);
/**
* Release a previously registered statement.
*
* @param statement The statement to release.
*/
public void release(Statement statement);
/**
* Register a JDBC result set.
*
* @param resultSet The result set to register.
*/
public void register(ResultSet resultSet);
/**
* Release a previously registered result set.
*
* @param resultSet The result set to release.
*/
public void release(ResultSet resultSet);
/**
* Does this registry currently have any registered resources?
*
* @return True if the registry does have registered resources; false otherwise.
*/
public boolean hasRegisteredResources();
/**
* Release all registered resources.
*/
public void releaseResources();
/**
* Close this registry. Also {@link #releaseResources releases} any registered resources.
* <p/>
* After execution, the registry is considered unusable.
*/
public void close();
}

View File

@ -0,0 +1,77 @@
/*
* 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.service.jdbc.spi;
import java.sql.Connection;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.dialect.Dialect;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.spi.Service;
/**
* Contract for services around JDBC operations. These represent shared resources, aka not varied by session/use.
*
* @author Steve Ebersole
*/
public interface JdbcServices extends Service {
/**
* Obtain service for providing JDBC connections.
*
* @return The connection provider.
*/
public ConnectionProvider getConnectionProvider();
/**
* Obtain the dialect of the database to which {@link Connection connections} from
* {@link #getConnectionProvider()} point.
*
* @return The database dialect.
*/
public Dialect getDialect();
/**
* Obtain service for logging SQL statements.
*
* @return The SQL statement logger.
*/
public SQLStatementLogger getSqlStatementLogger();
/**
* Obtain service for dealing with exceptions.
*
* @return The exception helper service.
*/
public SQLExceptionHelper getSqlExceptionHelper();
/**
* Obtain infomration about supported behavior reported by the JDBC driver.
* <p/>
* Yuck, yuck, yuck! Much prefer this to be part of a "basic settings" type object. See discussion
* on {@link org.hibernate.cfg.internal.JdbcServicesBuilder}
*
* @return
*/
public ExtractedDatabaseMetaData getExtractedMetaDataSupport();
}

View File

@ -0,0 +1,40 @@
/*
* 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.service.jdbc.spi;
/**
* Generic contract for wrapped JDBC objects.
*
* @param <T> One of either {@link java.sql.Connection}, {@link java.sql.Statement} or {@link java.sql.ResultSet}
*
* @author Steve Ebersole
*/
public interface JdbcWrapper<T> {
/**
* Retrieve the wrapped JDBC object.
*
* @return The wrapped object
*/
public T getWrappedObject();
}

View File

@ -0,0 +1,70 @@
/*
* 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.service.jdbc.spi;
import java.sql.Connection;
/**
* LogicalConnection contract
*
* @author Steve Ebersole
*/
public interface LogicalConnection {
/**
* Is this logical connection open? Another phraseology sometimes used is: "are we
* logically connected"?
*
* @return True if logically connected; false otherwise.
*/
public boolean isOpen();
/**
* Is this logical connection instance "physically" connected. Meaning
* do we currently internally have a cached connection.
*
* @return True if physically connected; false otherwise.
*/
public boolean isPhysicallyConnected();
/**
* Retrieves the connection currently "logically" managed by this LogicalConnectionImpl.
* <p/>
* Note, that we may need to obtain a connection to return here if a
* connection has either not yet been obtained (non-UserSuppliedConnectionProvider)
* or has previously been aggressively released.
*
* @return The current Connection.
*/
public Connection getConnection();
/**
* Release the underlying connection and clean up any other resources associated
* with this logical connection.
* <p/>
* This leaves the logical connection in a "no longer useable" state.
*
* @return The physical connection which was being used.
*/
public Connection close();
}

View File

@ -0,0 +1,85 @@
/*
* 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.service.jdbc.spi;
import org.hibernate.ConnectionReleaseMode;
/**
* The "internal" contract for LogicalConnection
*
* @author Steve Ebersole
*/
public interface LogicalConnectionImplementor extends LogicalConnection {
/**
* Obtains the JDBC services associated with this logical connection.
*
* @return JDBC services
*/
public JdbcServices getJdbcServices();
/**
* Obtains the JDBC resource registry associated with this logical connection.
*
* @return The JDBC resource registry.
*/
public JdbcResourceRegistry getResourceRegistry();
/**
* Add an observer interested in notification of connection events.
*
* @param observer The observer.
*/
public void addObserver(ConnectionObserver observer);
/**
* The release mode under which this logical connection is operating.
*
* @return the release mode.
*/
public ConnectionReleaseMode getConnectionReleaseMode();
/**
* Used to signify that a statement has completed execution which may
* indicate that this logical connection need to perform an
* aggressive release of its physical connection.
*/
public void afterStatementExecution();
/**
* Used to signify that a transaction has completed which may indicate
* that this logical connection need to perform an aggressive release
* of its physical connection.
*/
public void afterTransaction();
/**
* Manually (and temporarily) circumvent aggressive release processing.
*/
public void disableReleases();
/**
* Re-enable aggressive release processing (after a prior {@link #disableReleases()} call.
*/
public void enableReleases();
}

View File

@ -0,0 +1,212 @@
/*
* 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.service.jdbc.spi;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLWarning;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.JDBCException;
import org.hibernate.exception.SQLExceptionConverter;
import org.hibernate.exception.SQLStateConverter;
import org.hibernate.exception.ViolatedConstraintNameExtracter;
import org.hibernate.util.StringHelper;
/**
* Helper for handling SQLExceptions in various manners.
*
* @author Steve Ebersole
*/
public class SQLExceptionHelper {
private static final Logger log = LoggerFactory.getLogger( SQLExceptionHelper.class );
public static final String DEFAULT_EXCEPTION_MSG = "SQL Exception";
public static final String DEFAULT_WARNING_MSG = "SQL Warning";
public static final SQLExceptionConverter DEFAULT_CONVERTER = new SQLStateConverter(
new ViolatedConstraintNameExtracter() {
public String extractConstraintName(SQLException e) {
return null;
}
}
);
private SQLExceptionConverter sqlExceptionConverter;
/**
* Create an exception helper with a default exception converter.
*/
public SQLExceptionHelper() {
sqlExceptionConverter = DEFAULT_CONVERTER;
}
/**
* Create an exception helper with a specific exception converter.
*
* @param sqlExceptionConverter The exception converter to use.
*/
public SQLExceptionHelper(SQLExceptionConverter sqlExceptionConverter) {
this.sqlExceptionConverter = sqlExceptionConverter;
}
/**
* Access the current exception converter being used internally.
*
* @return The current exception converter.
*/
public SQLExceptionConverter getSqlExceptionConverter() {
return sqlExceptionConverter;
}
/**
* Inject the exception converter to use.
* <p/>
* NOTE : <tt>null</tt> is allowed and signifies to use the default.
*
* @param sqlExceptionConverter The converter to use.
*/
public void setSqlExceptionConverter(SQLExceptionConverter sqlExceptionConverter) {
this.sqlExceptionConverter = ( sqlExceptionConverter == null ? DEFAULT_CONVERTER : sqlExceptionConverter );
}
/**
* Convert an SQLException using the current converter, doing some logging first.
*
* @param sqle The exception to convert
* @param message An error message.
* @return The converted exception
*/
public JDBCException convert(SQLException sqle, String message) {
return convert( sqle, message, "n/a" );
}
/**
* Convert an SQLException using the current converter, doing some logging first.
*
* @param sqle The exception to convert
* @param message An error message.
* @param sql The SQL being executed when the exception occurred
* @return The converted exception
*/
public JDBCException convert(SQLException sqle, String message, String sql) {
logExceptions( sqle, message + " [" + sql + "]" );
return sqlExceptionConverter.convert( sqle, message, sql );
}
/**
* Log any {@link java.sql.SQLWarning}s registered with the connection.
*
* @param connection The connection to check for warnings.
*/
public void logAndClearWarnings(Connection connection) {
if ( log.isWarnEnabled() ) {
try {
logWarnings( connection.getWarnings() );
}
catch ( SQLException sqle ) {
//workaround for WebLogic
log.debug( "could not log warnings", sqle );
}
}
try {
//Sybase fail if we don't do that, sigh...
connection.clearWarnings();
}
catch ( SQLException sqle ) {
log.debug( "could not clear warnings", sqle );
}
}
/**
* Log the given (and any nested) warning.
*
* @param warning The warning
*/
public void logWarnings(SQLWarning warning) {
logWarnings( warning, null );
}
/**
* Log the given (and any nested) warning.
*
* @param warning The warning
* @param message The message text to use as a preamble.
*/
public void logWarnings(SQLWarning warning, String message) {
if ( log.isWarnEnabled() ) {
if ( log.isDebugEnabled() && warning != null ) {
message = StringHelper.isNotEmpty( message ) ? message : DEFAULT_WARNING_MSG;
log.debug( message, warning );
}
while ( warning != null ) {
StringBuffer buf = new StringBuffer( 30 )
.append( "SQL Warning: " )
.append( warning.getErrorCode() )
.append( ", SQLState: " )
.append( warning.getSQLState() );
log.warn( buf.toString() );
log.warn( warning.getMessage() );
warning = warning.getNextWarning();
}
}
}
/**
* Log the given (and any nested) exception.
*
* @param sqlException The exception to log
*/
public void logExceptions(SQLException sqlException) {
logExceptions( sqlException, null );
}
/**
* Log the given (and any nested) exception.
*
* @param sqlException The exception to log
* @param message The message text to use as a preamble.
*/
public void logExceptions(SQLException sqlException, String message) {
if ( log.isErrorEnabled() ) {
if ( log.isDebugEnabled() ) {
message = StringHelper.isNotEmpty( message ) ? message : DEFAULT_EXCEPTION_MSG;
log.debug( message, sqlException );
}
while ( sqlException != null ) {
StringBuffer buf = new StringBuffer( 30 )
.append( "SQL Error: " )
.append( sqlException.getErrorCode() )
.append( ", SQLState: " )
.append( sqlException.getSQLState() );
log.warn( buf.toString() );
log.error( sqlException.getMessage() );
sqlException = sqlException.getNextException();
}
}
}
}

View File

@ -0,0 +1,104 @@
/*
* 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.service.jdbc.spi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.jdbc.util.FormatStyle;
/**
* Centralize logging for SQL statements.
*
* @author Steve Ebersole
*/
public class SQLStatementLogger {
private static final Logger log = LoggerFactory.getLogger( SQLStatementLogger.class );
private boolean logToStdout;
private boolean format;
/**
* Constructs a new SQLStatementLogger instance.
*/
public SQLStatementLogger() {
this( false, false );
}
/**
* Constructs a new SQLStatementLogger instance.
*
* @param logToStdout Should we log to STDOUT in addition to our internal logger.
* @param format Should we format the statements prior to logging
*/
public SQLStatementLogger(boolean logToStdout, boolean format) {
this.logToStdout = logToStdout;
this.format = format;
}
/**
* Are we currently logging to stdout?
*
* @return True if we are currently logging to stdout; false otherwise.
*/
public boolean isLogToStdout() {
return logToStdout;
}
/**
* Enable (true) or disable (false) logging to stdout.
*
* @param logToStdout True to enable logging to stdout; false to disable.
*/
public void setLogToStdout(boolean logToStdout) {
this.logToStdout = logToStdout;
}
public boolean isFormat() {
return format;
}
public void setFormat(boolean format) {
this.format = format;
}
/**
* Log a SQL statement string.
*
* @param statement The SQL statement.
*/
public void logStatement(String statement) {
// for now just assume a DML log for formatting
if ( format ) {
if ( logToStdout || log.isDebugEnabled() ) {
statement = FormatStyle.BASIC.getFormatter().format( statement );
}
}
log.debug( statement );
if ( logToStdout ) {
System.out.println( "Hibernate: " + statement );
}
}
}

View File

@ -0,0 +1,42 @@
/*
* 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.service.jdbc.spi;
import java.sql.Connection;
/**
* Contract for resolving the schema of a {@link Connection}.
*
* @author Steve Ebersole
*/
public interface SchemaNameResolver {
/**
* Given a JDBC {@link Connection}, resolve the name of the schema (if one) to which it connects.
*
* @param connection The JDBC connection
*
* @return The name of the schema (may be null).
*/
public String resolveSchemaName(Connection connection);
}