/**
* Copyright 2010 JBoss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package bitronix.tm.resource.jdbc;
import bitronix.tm.resource.common.TransactionContextHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import java.sql.*;
import java.util.Map;
/**
* Disposable Connection handle.
* <p>© <a href="http://www.bitronix.be">Bitronix Software</a></p>
*
* @author lorban
*/
public class JdbcConnectionHandle implements Connection {
private final static Logger log = LoggerFactory.getLogger(JdbcConnectionHandle.class);
private JdbcPooledConnection jdbcPooledConnection;
private Connection delegate;
public JdbcConnectionHandle(JdbcPooledConnection jdbcPooledConnection, Connection connection) {
this.jdbcPooledConnection = jdbcPooledConnection;
this.delegate = connection;
}
public JdbcPooledConnection getPooledConnection() {
return jdbcPooledConnection;
}
private Connection getDelegate() throws SQLException {
if (jdbcPooledConnection == null)
throw new SQLException("connection is closed");
return delegate;
}
public Connection getConnection() {
return delegate;
}
public String toString() {
return "a JdbcConnectionHandle of " + jdbcPooledConnection + " on " + delegate;
}
/**
* Enlist this connection into the current transaction if automaticEnlistingEnabled = true for this resource.
* If no transaction is running then this method does nothing.
* @throws SQLException thrown when an error occurs during elistment.
*/
private void enlistResource() throws SQLException {
if (jdbcPooledConnection == null)
throw new SQLException("connection handle already closed");
if (jdbcPooledConnection.getPoolingDataSource().getAutomaticEnlistingEnabled()) {
try {
TransactionContextHelper.enlistInCurrentTransaction(jdbcPooledConnection, jdbcPooledConnection.getPoolingDataSource());
} catch (SystemException ex) {
throw (SQLException) new SQLException("error enlisting " + this).initCause(ex);
} catch (RollbackException ex) {
throw (SQLException) new SQLException("error enlisting " + this).initCause(ex);
}
} // if getAutomaticEnlistingEnabled
}
/* wrapped Connection methods that have special XA semantics */
public void close() throws SQLException {
if (log.isDebugEnabled()) log.debug("closing " + this);
// in case the connection has already been closed
if (jdbcPooledConnection == null)
return;
jdbcPooledConnection.release();
jdbcPooledConnection = null;
}
public void commit() throws SQLException {
if (jdbcPooledConnection == null)
throw new SQLException("connection handle already closed");
if (jdbcPooledConnection.isParticipatingInActiveGlobalTransaction())
throw new SQLException("cannot commit a resource enlisted in a global transaction");
getDelegate().commit();
}
public void rollback() throws SQLException {
if (jdbcPooledConnection == null)
throw new SQLException("connection handle already closed");
if (jdbcPooledConnection.isParticipatingInActiveGlobalTransaction())
throw new SQLException("cannot rollback a resource enlisted in a global transaction");
getDelegate().rollback();
}
public void rollback(Savepoint savepoint) throws SQLException {
if (jdbcPooledConnection == null)
throw new SQLException("connection handle already closed");
if (jdbcPooledConnection.isParticipatingInActiveGlobalTransaction())
throw new SQLException("cannot rollback a resource enlisted in a global transaction");
getDelegate().rollback(savepoint);
}
public Savepoint setSavepoint() throws SQLException {
if (jdbcPooledConnection == null)
throw new SQLException("connection handle already closed");
if (jdbcPooledConnection.isParticipatingInActiveGlobalTransaction())
throw new SQLException("cannot set a savepoint on a resource enlisted in a global transaction");
return getDelegate().setSavepoint();
}
public Savepoint setSavepoint(String name) throws SQLException {
if (jdbcPooledConnection == null)
throw new SQLException("connection handle already closed");
if (jdbcPooledConnection.isParticipatingInActiveGlobalTransaction())
throw new SQLException("cannot set a savepoint on a resource enlisted in a global transaction");
return getDelegate().setSavepoint(name);
}
public void releaseSavepoint(Savepoint savepoint) throws SQLException {
if (jdbcPooledConnection == null)
throw new SQLException("connection handle already closed");
if (jdbcPooledConnection.isParticipatingInActiveGlobalTransaction())
throw new SQLException("cannot release a savepoint on a resource enlisted in a global transaction");
getDelegate().releaseSavepoint(savepoint);
}
public boolean getAutoCommit() throws SQLException {
if (jdbcPooledConnection == null)
throw new SQLException("connection handle already closed");
if (jdbcPooledConnection.isParticipatingInActiveGlobalTransaction())
return false;
return getDelegate().getAutoCommit();
}
public void setAutoCommit(boolean autoCommit) throws SQLException {
if (jdbcPooledConnection == null)
throw new SQLException("connection handle already closed");
if (!jdbcPooledConnection.isParticipatingInActiveGlobalTransaction())
getDelegate().setAutoCommit(autoCommit);
else if (autoCommit)
throw new SQLException("autocommit is not allowed on a resource enlisted in a global transaction");
}
public boolean isClosed() throws SQLException {
if (jdbcPooledConnection == null)
return true;
return getDelegate().isClosed();
}
public Statement createStatement() throws SQLException {
enlistResource();
return jdbcPooledConnection.registerUncachedStatement(getDelegate().createStatement());
}
public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
enlistResource();
return jdbcPooledConnection.registerUncachedStatement(getDelegate().createStatement(resultSetType, resultSetConcurrency));
}
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
enlistResource();
return jdbcPooledConnection.registerUncachedStatement(getDelegate().createStatement(resultSetType, resultSetConcurrency, resultSetHoldability));
}
public CallableStatement prepareCall(String sql) throws SQLException {
enlistResource();
return (CallableStatement) jdbcPooledConnection.registerUncachedStatement(getDelegate().prepareCall(sql));
}
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
enlistResource();
return (CallableStatement) jdbcPooledConnection.registerUncachedStatement(getDelegate().prepareCall(sql, resultSetType, resultSetConcurrency));
}
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
enlistResource();
return (CallableStatement) jdbcPooledConnection.registerUncachedStatement(getDelegate().prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
}
/* PreparedStatement cache aware methods */
public PreparedStatement prepareStatement(String sql) throws SQLException {
enlistResource();
PreparedStatement stmt;
boolean useStatementCache = getPooledConnection().getPoolingDataSource().getPreparedStatementCacheSize() > 0;
if (useStatementCache) {
stmt = getPooledConnection().getCachedStatement(sql);
if (stmt == null) {
stmt = getDelegate().prepareStatement(sql);
getPooledConnection().putCachedStatement(sql, stmt);
}
stmt = new JdbcPreparedStatementHandle(stmt);
}
else {
stmt = (PreparedStatement) jdbcPooledConnection.registerUncachedStatement(getDelegate().prepareStatement(sql));
}
return stmt;
}
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
enlistResource();
PreparedStatement stmt;
boolean useStatementCache = getPooledConnection().getPoolingDataSource().getPreparedStatementCacheSize() > 0;
if (useStatementCache) {
stmt = getPooledConnection().getCachedStatement(sql);
if (stmt == null) {
stmt = getDelegate().prepareStatement(sql, autoGeneratedKeys);
getPooledConnection().putCachedStatement(sql, stmt);
}
stmt = new JdbcPreparedStatementHandle(stmt);
}
else {
stmt = (PreparedStatement) jdbcPooledConnection.registerUncachedStatement(getDelegate().prepareStatement(sql, autoGeneratedKeys));
}
return stmt;
}
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
enlistResource();
PreparedStatement stmt;
boolean useStatementCache = getPooledConnection().getPoolingDataSource().getPreparedStatementCacheSize() > 0;
if (useStatementCache) {
stmt = getPooledConnection().getCachedStatement(sql);
if (stmt == null) {
stmt = getDelegate().prepareStatement(sql, resultSetType, resultSetConcurrency);
getPooledConnection().putCachedStatement(sql, stmt);
}
stmt = new JdbcPreparedStatementHandle(stmt);
}
else {
stmt = (PreparedStatement) jdbcPooledConnection.registerUncachedStatement(getDelegate().prepareStatement(sql, resultSetType, resultSetConcurrency));
}
return stmt;
}
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
enlistResource();
PreparedStatement stmt;
boolean useStatementCache = getPooledConnection().getPoolingDataSource().getPreparedStatementCacheSize() > 0;
if (useStatementCache) {
stmt = getPooledConnection().getCachedStatement(sql);
if (stmt == null) {
stmt = getDelegate().prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
getPooledConnection().putCachedStatement(sql, stmt);
}
stmt = new JdbcPreparedStatementHandle(stmt);
}
else {
stmt = (PreparedStatement) jdbcPooledConnection.registerUncachedStatement(getDelegate().prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
}
return stmt;
}
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
enlistResource();
PreparedStatement stmt;
boolean useStatementCache = getPooledConnection().getPoolingDataSource().getPreparedStatementCacheSize() > 0;
if (useStatementCache) {
stmt = getPooledConnection().getCachedStatement(sql);
if (stmt == null) {
stmt = getDelegate().prepareStatement(sql, columnIndexes);
getPooledConnection().putCachedStatement(sql, stmt);
}
stmt = new JdbcPreparedStatementHandle(stmt);
}
else {
stmt = (PreparedStatement) jdbcPooledConnection.registerUncachedStatement(getDelegate().prepareStatement(sql, columnIndexes));
}
return stmt;
}
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
enlistResource();
PreparedStatement stmt;
boolean useStatementCache = getPooledConnection().getPoolingDataSource().getPreparedStatementCacheSize() > 0;
if (useStatementCache) {
stmt = getPooledConnection().getCachedStatement(sql);
if (stmt == null) {
stmt = getDelegate().prepareStatement(sql, columnNames);
getPooledConnection().putCachedStatement(sql, stmt);
}
stmt = new JdbcPreparedStatementHandle(stmt);
}
else {
stmt = (PreparedStatement) jdbcPooledConnection.registerUncachedStatement(getDelegate().prepareStatement(sql, columnNames));
}
return stmt;
}
/* delegates of Connection methods */
public int getHoldability() throws SQLException {
return getDelegate().getHoldability();
}
public int getTransactionIsolation() throws SQLException {
return getDelegate().getTransactionIsolation();
}
public void clearWarnings() throws SQLException {
getDelegate().clearWarnings();
}
public boolean isReadOnly() throws SQLException {
return getDelegate().isReadOnly();
}
public void setHoldability(int holdability) throws SQLException {
getDelegate().setHoldability(holdability);
}
public void setTransactionIsolation(int level) throws SQLException {
getDelegate().setTransactionIsolation(level);
}
public void setReadOnly(boolean readOnly) throws SQLException {
getDelegate().setReadOnly(readOnly);
}
public String getCatalog() throws SQLException {
return getDelegate().getCatalog();
}
public void setCatalog(String catalog) throws SQLException {
getDelegate().setCatalog(catalog);
}
public DatabaseMetaData getMetaData() throws SQLException {
return getDelegate().getMetaData();
}
public SQLWarning getWarnings() throws SQLException {
return getDelegate().getWarnings();
}
public Map getTypeMap() throws SQLException {
return getDelegate().getTypeMap();
}
public void setTypeMap(Map map) throws SQLException {
getDelegate().setTypeMap(map);
}
public String nativeSQL(String sql) throws SQLException {
return getDelegate().nativeSQL(sql);
}
}