📄 xaclientconnection.java
字号:
/*
* Licensed under the X license (see http://www.x.org/terms.htm)
*/
package org.ofbiz.minerva.pool.jdbc.xa.wrapper;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Savepoint;
import java.sql.Statement;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
import org.ofbiz.minerva.pool.PoolEvent;
import org.ofbiz.minerva.pool.cache.LeastRecentlyUsedCache;
import org.ofbiz.minerva.pool.cache.ObjectCache;
import org.ofbiz.minerva.pool.jdbc.ConnectionInPool;
import org.ofbiz.minerva.pool.jdbc.ConnectionWrapper;
import org.ofbiz.minerva.pool.jdbc.PreparedStatementFactory;
import org.ofbiz.minerva.pool.jdbc.PreparedStatementInPool;
import org.ofbiz.minerva.pool.jdbc.StatementInPool;
import org.apache.log4j.Logger;
/**
* Wrapper for database connections used by an XAConnection. When close is
* called, it does not close the underlying connection, just informs the
* XAConnection that close was called. The connection will not be closed (or
* returned to the pool) until the transactional details are taken care of.
* This instance only lives as long as one client is using it - though we
* probably want to consider reusing it to save object allocations.
*
* @author Aaron Mulder (ammulder@alumni.princeton.edu)
*/
public class XAClientConnection implements ConnectionWrapper {
private final static String CLOSED = "Connection has been closed!";
private Connection con;
private HashSet statements;
private Vector listeners;
private XAConnectionImpl xaCon;
private int preparedStatementCacheSize = 0;
private ObjectCache preparedStatementCache;
private String stackTrace = null;
private static Logger log = Logger.getLogger(XADataSourceImpl.class);
/**
* Creates a new connection wrapper.
* @param xaCon The handler for all the transactional details.
* @param con The "real" database connection to wrap.
*/
public XAClientConnection(XAConnectionImpl xaCon, Connection con, boolean saveStackTrace) {
this.con = con;
this.xaCon = xaCon;
preparedStatementCache = (ObjectCache) ConnectionInPool.psCaches.get(con);
if (preparedStatementCache == null) {
PreparedStatementFactory factory = new PreparedStatementFactory(con);
preparedStatementCache = new LeastRecentlyUsedCache(factory, preparedStatementCacheSize);
ConnectionInPool.psCaches.put(con, preparedStatementCache);
}
statements = new HashSet();
listeners = new Vector();
if (saveStackTrace) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream stream = new PrintStream(baos);
new Throwable().printStackTrace(stream);
baos.close();
stackTrace = baos.toString();
} catch (Exception ex) {
}
}
}
/**
* Sets the number of PreparedStatements to be cached for each
* Connection. Your DB product may impose a limit on the number
* of open PreparedStatements.
*/
public void setPSCacheSize(int maxSize) {
preparedStatementCacheSize = maxSize;
if (preparedStatementCache != null) {
preparedStatementCache.setSize(maxSize);
}
}
/**
* Gets the number of PreparedStatements to be cached for each
* Connection.
*/
public int getPSCacheSize() {
return preparedStatementCacheSize;
}
/**
* Gets a reference to the "real" connection. This should only be used if
* you need to cast that to a specific type to call a proprietary method -
* you will defeat all the pooling if you use the underlying connection
* directly.
*/
public Connection getUnderlyingConnection() {
return con;
}
/**
* Closes this connection wrapper permanently. All further calls with throw
* a SQLException.
*/
public void shutdown() {
con = null;
statements = null;
listeners = null;
xaCon = null;
}
/**
* Updates the last used time for this connection to the current time.
* This is not used by the current implementation.
*/
public void setLastUsed() {
xaCon.firePoolEvent(new PoolEvent(xaCon, PoolEvent.OBJECT_USED));
}
/**
* Indicates that an error occured on this connection.
*/
public void setError(SQLException e) {
xaCon.setConnectionError(e);
}
/**
* Indicates that a statement has been closed and no longer needs to be
* tracked. Outstanding statements are closed when the connection is
* returned to the pool.
*/
public void statementClosed(Statement st) {
statements.remove(st);
if ((con != null) && (st instanceof PreparedStatementInPool) && preparedStatementCacheSize != 0) {
// Now return the "real" statement to the pool
PreparedStatementInPool ps = (PreparedStatementInPool) st;
PreparedStatement ups = ps.getUnderlyingPreparedStatement();
preparedStatementCache.returnObject(ps.getSql(), ups);
/*
int rsType = ResultSet.TYPE_FORWARD_ONLY;
int rsConcur = ResultSet.CONCUR_READ_ONLY;
// We may have JDBC 1.0 driver
try {
rsType = ups.getResultSetType();
rsConcur = ups.getResultSetConcurrency();
} catch (Throwable th) {
}
PreparedStatementInPool.preparedStatementCache.put(
new PSCacheKey(con, ps.getSql(), rsType, rsConcur), ups);
*/
}
}
// ---- Implementation of java.sql.Connection ----
public Statement createStatement() throws SQLException {
if (con == null) throw new SQLException(CLOSED);
try {
StatementInPool st = new StatementInPool(con.createStatement(), this);
statements.add(st);
return st;
} catch (SQLException e) {
setError(e);
throw e;
}
}
public PreparedStatement prepareStatement(String sql) throws SQLException {
if (con == null) throw new SQLException(CLOSED);
try {
PreparedStatement ps;
if (preparedStatementCacheSize == 0) {
// cache disabled
ps = con.prepareStatement(sql);
} else {
ps = (PreparedStatement) preparedStatementCache.useObject(sql);
}
if (ps == null)
throw new SQLException("Unable to create PreparedStatement!");
PreparedStatementInPool wrapper = new PreparedStatementInPool(ps, this, sql);
statements.add(wrapper);
return wrapper;
} catch (SQLException e) {
setError(e);
throw e;
}
}
public CallableStatement prepareCall(String sql) throws SQLException {
if (con == null) throw new SQLException(CLOSED);
try {
return con.prepareCall(sql);
} catch (SQLException e) {
setError(e);
throw e;
}
}
public String nativeSQL(String sql) throws SQLException {
if (con == null) throw new SQLException(CLOSED);
try {
return con.nativeSQL(sql);
} catch (SQLException e) {
setError(e);
throw e;
}
}
public void setAutoCommit(boolean autoCommit) throws SQLException {
if (con == null) throw new SQLException(CLOSED);
if (((XAResourceImpl) xaCon.getXAResource()).isTransaction() && autoCommit)
throw new SQLException("Cannot set AutoCommit for a transactional connection: See JDBC 2.0 Optional Package Specification section 7.1 (p25)");
try {
con.setAutoCommit(autoCommit);
} catch (SQLException e) {
setError(e);
throw e;
}
}
public boolean getAutoCommit() throws SQLException {
if (con == null) throw new SQLException(CLOSED);
try {
return con.getAutoCommit();
} catch (SQLException e) {
setError(e);
throw e;
}
}
public void commit() throws SQLException {
if (con == null) throw new SQLException(CLOSED);
if (((XAResourceImpl) xaCon.getXAResource()).isTransaction())
throw new SQLException("Cannot commit a transactional connection: See JDBC 2.0 Optional Package Specification section 7.1 (p25)");
try {
con.commit();
} catch (SQLException e) {
setError(e);
throw e;
}
}
public void rollback() throws SQLException {
if (con == null) throw new SQLException(CLOSED);
if (((XAResourceImpl) xaCon.getXAResource()).isTransaction())
throw new SQLException("Cannot rollback a transactional connection: See JDBC 2.0 Optional Package Specification section 7.1 (p25)");
}
public void forcedClose() throws SQLException {
if (stackTrace != null)
System.err.println("A forced close because a non-closed connection:\n" + stackTrace);
if (con == null) throw new SQLException(CLOSED);
Collection copy = (Collection) statements.clone();
Iterator it = copy.iterator();
while (it.hasNext())
try {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -