package com.mchange.v2.c3p0.impl;
import java.lang.reflect.*;
import java.sql.*;
import java.util.*;
import javax.sql.*;
import com.mchange.v2.log.*;
import com.mchange.v2.sql.*;
import com.mchange.v2.sql.filter.*;
import com.mchange.v2.c3p0.*;
import com.mchange.v2.c3p0.stmt.*;
import com.mchange.v2.c3p0.C3P0ProxyConnection;
import com.mchange.v2.c3p0.util.ConnectionEventSupport;
import com.mchange.v2.c3p0.util.StatementEventSupport;
import com.mchange.v2.lang.ObjectUtils;
public final class C3P0PooledConnection extends AbstractC3P0PooledConnection
{
final static MLogger logger = MLog.getLogger( C3P0PooledConnection.class );
final static Class[] PROXY_CTOR_ARGS = new Class[]{ InvocationHandler.class };
final static Constructor CON_PROXY_CTOR;
final static Method RS_CLOSE_METHOD;
final static Method STMT_CLOSE_METHOD;
final static Object[] CLOSE_ARGS;
final static Set OBJECT_METHODS;
private static Constructor createProxyConstructor(Class intfc) throws NoSuchMethodException
{
Class[] proxyInterfaces = new Class[] { intfc };
Class proxyCl = Proxy.getProxyClass(C3P0PooledConnection.class.getClassLoader(), proxyInterfaces);
return proxyCl.getConstructor( PROXY_CTOR_ARGS );
}
static
{
try
{
CON_PROXY_CTOR = createProxyConstructor( ProxyConnection.class );
Class[] argClasses = new Class[0];
RS_CLOSE_METHOD = ResultSet.class.getMethod("close", argClasses);
STMT_CLOSE_METHOD = Statement.class.getMethod("close", argClasses);
CLOSE_ARGS = new Object[0];
OBJECT_METHODS = Collections.unmodifiableSet( new HashSet( Arrays.asList( Object.class.getMethods() ) ) );
}
catch (Exception e)
{
logger.log(MLevel.SEVERE, "An Exception occurred in static initializer of" + C3P0PooledConnection.class.getName(), e);
throw new InternalError("Something is very wrong, or this is a pre 1.3 JVM." +
"We cannot set up dynamic proxies and/or methods!");
}
}
final ConnectionTester connectionTester;
final boolean autoCommitOnClose;
final boolean forceIgnoreUnresolvedTransactions;
final boolean supports_setTypeMap;
final boolean supports_setHoldability;
final int dflt_txn_isolation;
final String dflt_catalog;
final int dflt_holdability;
final ConnectionEventSupport ces = new ConnectionEventSupport(this);
final StatementEventSupport ses = new StatementEventSupport(this);
volatile Connection physicalConnection;
volatile Exception invalidatingException = null;
ProxyConnection exposedProxy;
int connection_status = ConnectionTester.CONNECTION_IS_OKAY;
final Set uncachedActiveStatements = Collections.synchronizedSet( new HashSet() );
volatile GooGooStatementCache scache;
volatile boolean isolation_lvl_nondefault = false;
volatile boolean catalog_nondefault = false;
volatile boolean holdability_nondefault = false;
public C3P0PooledConnection(Connection con,
ConnectionTester connectionTester,
boolean autoCommitOnClose,
boolean forceIgnoreUnresolvedTransactions,
ConnectionCustomizer cc,
String pdsIdt) throws SQLException
{
try
{
if (cc != null)
cc.onAcquire( con, pdsIdt );
}
catch (Exception e)
{ throw SqlUtils.toSQLException(e); }
this.physicalConnection = con;
this.connectionTester = connectionTester;
this.autoCommitOnClose = autoCommitOnClose;
this.forceIgnoreUnresolvedTransactions = forceIgnoreUnresolvedTransactions;
this.supports_setTypeMap = C3P0ImplUtils.supportsMethod(con, "setTypeMap", new Class[]{ Map.class });
this.supports_setHoldability = C3P0ImplUtils.supportsMethod(con, "setHoldability", new Class[]{ int.class });
this.dflt_txn_isolation = con.getTransactionIsolation();
this.dflt_catalog = con.getCatalog();
this.dflt_holdability = (supports_setHoldability ? con.getHoldability() : ResultSet.CLOSE_CURSORS_AT_COMMIT);
}
Connection getPhysicalConnection()
{ return physicalConnection; }
boolean isClosed() throws SQLException
{ return (physicalConnection == null); }
void initStatementCache( GooGooStatementCache scache )
{ this.scache = scache; }
public synchronized Connection getConnection()
throws SQLException
{
if ( exposedProxy != null)
{
logger.warning("c3p0 -- Uh oh... getConnection() was called on a PooledConnection when " +
"it had already provided a client with a Connection that has not yet been " +
"closed. This probably indicates a bug in the connection pool!!!");
return exposedProxy;
}
else
{ return getCreateNewConnection(); }
}
private Connection getCreateNewConnection()
throws SQLException
{
try
{
ensureOkay();
return (exposedProxy = createProxyConnection());
}
catch (SQLException e)
{ throw e; }
catch (Exception e)
{
logger.log(MLevel.WARNING, "Failed to acquire connection!", e);
throw new SQLException("Failed to acquire connection!");
}
}
public void closeAll() throws SQLException
{
if (scache != null)
scache.closeAll( physicalConnection );
}
public void close() throws SQLException
{ this.close( false ); }
synchronized void closeMaybeCheckedOut( boolean checked_out ) throws SQLException
{
if ( checked_out )
{
try { C3P0ImplUtils.resetTxnState( physicalConnection, forceIgnoreUnresolvedTransactions, autoCommitOnClose, false ); }
catch (Exception e)
{
if (logger.isLoggable( MLevel.FINER ))
logger.log( MLevel.FINER,
"Failed to reset the transaction state of " + physicalConnection + "just prior to close(). " +
"Only relevant at all if this was a Connection being forced close()ed midtransaction.",
e );
}
}
close( false );
}
private synchronized void close(boolean known_invalid) throws SQLException
{
if ( physicalConnection != null )
{
try
{
StringBuffer debugOnlyLog = null;
if ( Debug.DEBUG && known_invalid )
{
debugOnlyLog = new StringBuffer();
debugOnlyLog.append("[ exceptions: ");
}
Exception exc = cleanupUncachedActiveStatements();
if (Debug.DEBUG && exc != null)
{
if (known_invalid)
debugOnlyLog.append( exc.toString() + ' ' );
else
logger.log(MLevel.WARNING, "An exception occurred while cleaning up uncached active Statements.", exc);
}
try
{
if (exposedProxy != null)
exposedProxy.silentClose( known_invalid );
}
catch (Exception e)
{
if (Debug.DEBUG)
{
if (known_invalid)
debugOnlyLog.append( e.toString() + ' ' );
else
logger.log(MLevel.WARNING, "An exception occurred.", exc);
}
exc = e;
}
try
{ this.closeAll(); }
catch (Exception e)
{
if (Debug.DEBUG)
{
if (known_invalid)
debugOnlyLog.append( e.toString() + ' ' );
else
logger.log(MLevel.WARNING, "An exception occurred.", exc);
}
exc = e;
}
try { physicalConnection.close(); }
catch (Exception e)
{
if (Debug.DEBUG)
{
if (known_invalid)
debugOnlyLog.append( e.toString() + ' ' );
else
logger.log(MLevel.WARNING, "An exception occurred.", exc);
e.printStackTrace();
}
exc = e;
}
if (exc != null)
{
if (known_invalid)
{
debugOnlyLog.append(" ]");
if (Debug.DEBUG)
{
logger.fine(this + ": while closing a PooledConnection known to be invalid, " +
" some exceptions occurred. This is probably not a problem: " +
debugOnlyLog.toString() );
}
}
else
throw new SQLException("At least one error occurred while attempting " +
"to close() the PooledConnection: " + exc);
}
if (Debug.TRACE == Debug.TRACE_MAX)
logger.fine("C3P0PooledConnection closed. [" + this + ']');
}
finally
{ physicalConnection = null; }
}
}
public void addConnectionEventListener(ConnectionEventListener listener)
{ ces.addConnectionEventListener( listener ); }
public void removeConnectionEventListener(ConnectionEventListener listener)
{ ces.removeConnectionEventListener( listener ); }
public void addStatementEventListener(StatementEventListener sel)
{
if (logger.isLoggable( MLevel.INFO ))
logger.info( "Per the JDBC4 spec, " + this.getClass().getName() +
" accepts StatementListeners, but for now there is no circumstance under which they are notified!" );
ses.addStatementEventListener( sel );
}
public void removeStatementEventListener(StatementEventListener sel)
{
ses.removeStatementEventListener( sel );
}
private void reset() throws SQLException
{ reset( false ); }
private void reset( boolean known_resolved_txn ) throws SQLException
{
ensureOkay();
C3P0ImplUtils.resetTxnState( physicalConnection, forceIgnoreUnresolvedTransactions, autoCommitOnClose, known_resolved_txn );
if (isolation_lvl_nondefault)
{
physicalConnection.setTransactionIsolation( dflt_txn_isolation );
isolation_lvl_nondefault = false;
}
if (catalog_nondefault)
{
physicalConnection.setCatalog( dflt_catalog );
catalog_nondefault = false;
}
if (holdability_nondefault)
{
physicalConnection.setHoldability( dflt_holdability );
holdability_nondefault = false;
}
try
{ physicalConnection.setReadOnly( false ); }
catch ( Throwable t )
{
if (logger.isLoggable( MLevel.FINE ))
logger.log(MLevel.FINE, "A Throwable occurred while trying to reset the readOnly property of our Connection to false!", t);
}
try
{ if (supports_setTypeMap) physicalConnection.setTypeMap( Collections.EMPTY_MAP ); }
catch ( Throwable t )
{
if (logger.isLoggable( MLevel.FINE ))
logger.log(MLevel.FINE, "A Throwable occurred while trying to reset the typeMap property of our Connection to Collections.EMPTY_MAP!", t);
}
}
boolean closeAndRemoveResultSets(Set rsSet)
{
boolean okay = true;
synchronized (rsSet)
{
for (Iterator ii = rsSet.iterator(); ii.hasNext(); )
{
ResultSet rs = (ResultSet) ii.next();
try
{ rs.close(); }
catch (SQLException e)
{
if (Debug.DEBUG)
logger.log(MLevel.WARNING, "An exception occurred while cleaning up a ResultSet.", e);
okay = false;
}
finally
{ ii.remove(); }
}
}
return okay;
}
void ensureOkay() throws SQLException
{
if (physicalConnection == null)
throw new SQLException( invalidatingException == null ?
"Connection is closed or broken." :
"Connection is broken. Invalidating Exception: " + invalidatingException.toString());
}
boolean closeAndRemoveResourcesInSet(Set s, Method closeMethod)
{
boolean okay = true;
Set temp;
synchronized (s)
{ temp = new HashSet( s ); }
for (Iterator ii = temp.iterator(); ii.hasNext(); )
{
Object rsrc = ii.next();
try
{ closeMethod.invoke(rsrc, CLOSE_ARGS); }
catch (Exception e)
{
Throwable t = e;
if (t instanceof InvocationTargetException)
t = ((InvocationTargetException) e).getTargetException();
logger.log(MLevel.WARNING, "An exception occurred while cleaning up a resource.", t);
okay = false;
}
finally
{ s.remove( rsrc ); }
}
return okay;
}
private SQLException cleanupUncachedActiveStatements()
{
boolean okay = closeAndRemoveResourcesInSet(uncachedActiveStatements, STMT_CLOSE_METHOD);
if (okay)
return null;
else
return new SQLException("An exception occurred while trying to " +
"clean up orphaned resources.");
}
ProxyConnection createProxyConnection() throws Exception
{
InvocationHandler handler = new ProxyConnectionInvocationHandler();
return (ProxyConnection) CON_PROXY_CTOR.newInstance( new Object[] {handler} );
}
Statement createProxyStatement( Statement innerStmt ) throws Exception
{ return this.createProxyStatement( false, innerStmt ); }
private static class StatementProxyingSetManagedResultSet extends SetManagedResultSet
{
private Statement proxyStatement;
StatementProxyingSetManagedResultSet(Set activeResultSets)
{ super( activeResultSets ); }
public void setProxyStatement( Statement proxyStatement )
{ this.proxyStatement = proxyStatement; }
public Statement getStatement() throws SQLException
{ return (proxyStatement == null ? super.getStatement() : proxyStatement); }
}
Statement createProxyStatement(
final boolean inner_is_cached,
final Statement innerStmt) throws Exception
{
final Set activeResultSets = Collections.synchronizedSet( new HashSet() );
final Connection parentConnection = exposedProxy;
if (Debug.DEBUG && parentConnection == null)
{
logger.warning("PROBABLE C3P0 BUG -- " +
this + ": created a proxy Statement when there is no active, exposed proxy Connection???");
}
final StatementProxyingSetManagedResultSet mainResultSet = new StatementProxyingSetManagedResultSet( activeResultSets );
class WrapperStatementHelper
{
Statement wrapperStmt;
Statement nakedInner;
public WrapperStatementHelper(Statement wrapperStmt, Statement nakedInner)
{
this.wrapperStmt = wrapperStmt;
this.nakedInner = nakedInner;
if (! inner_is_cached)
uncachedActiveStatements.add( wrapperStmt );
}
private boolean closeAndRemoveActiveResultSets()
{ return closeAndRemoveResultSets( activeResultSets ); }
public ResultSet wrap(ResultSet rs)
{
if (mainResultSet.getInner() == null)
{
mainResultSet.setInner(rs);
mainResultSet.setProxyStatement( wrapperStmt );
return mainResultSet;
}
else
{
StatementProxyingSetManagedResultSet out
= new StatementProxyingSetManagedResultSet( activeResultSets );
out.setInner( rs );
out.setProxyStatement( wrapperStmt );
return out;
}
}
public void doClose()
throws SQLException
{
boolean okay = closeAndRemoveActiveResultSets();
if (inner_is_cached)
scache.checkinStatement( innerStmt );
else
{
innerStmt.close();
uncachedActiveStatements.remove( wrapperStmt );
}
if (!okay)
throw new SQLException("Failed to close an orphaned ResultSet properly.");
}
public Object doRawStatementOperation(Method m, Object target, Object[] args)
throws IllegalAccessException, InvocationTargetException, SQLException
{
if (target == C3P0ProxyStatement.RAW_STATEMENT)
target = nakedInner;
for (int i = 0, len = args.length; i < len; ++i)
if (args[i] == C3P0ProxyStatement.RAW_STATEMENT)
args[i] = nakedInner;
Object out = m.invoke(target, args);
if (out instanceof ResultSet)
out = wrap( (ResultSet) out );
return out;
}
}
if (innerStmt instanceof CallableStatement)
{
class ProxyCallableStatement extends FilterCallableStatement implements C3P0ProxyStatement
{
WrapperStatementHelper wsh;
ProxyCallableStatement(CallableStatement is)
{
super( is );
this.wsh = new WrapperStatementHelper(this, is);
}
public Connection getConnection()
{ return parentConnection; }
public ResultSet getResultSet() throws SQLException
{ return wsh.wrap( super.getResultSet() ); }
public ResultSet getGeneratedKeys() throws SQLException
{ return wsh.wrap( super.getGeneratedKeys() ); }
public ResultSet executeQuery(String sql) throws SQLException
{ return wsh.wrap( super.executeQuery(sql) ); }
public ResultSet executeQuery() throws SQLException
{ return wsh.wrap( super.executeQuery() ); }
public Object rawStatementOperation(Method m, Object target, Object[] args)
throws IllegalAccessException, InvocationTargetException, SQLException
{ return wsh.doRawStatementOperation( m, target, args); }
public void close() throws SQLException
{ wsh.doClose(); }
}
return new ProxyCallableStatement((CallableStatement) innerStmt );
}
else if (innerStmt instanceof PreparedStatement)
{
class ProxyPreparedStatement extends FilterPreparedStatement implements C3P0ProxyStatement
{
WrapperStatementHelper wsh;
ProxyPreparedStatement(PreparedStatement ps)
{
super( ps );
this.wsh = new WrapperStatementHelper(this, ps);
}
public Connection getConnection()
{ return parentConnection; }
public ResultSet getResultSet() throws SQLException
{ return wsh.wrap( super.getResultSet() ); }
public ResultSet getGeneratedKeys() throws SQLException
{ return wsh.wrap( super.getGeneratedKeys() ); }
public ResultSet executeQuery(String sql) throws SQLException
{ return wsh.wrap( super.executeQuery(sql) ); }
public ResultSet executeQuery() throws SQLException
{ return wsh.wrap( super.executeQuery() ); }
public Object rawStatementOperation(Method m, Object target, Object[] args)
throws IllegalAccessException, InvocationTargetException, SQLException
{ return wsh.doRawStatementOperation( m, target, args); }
public void close() throws SQLException
{ wsh.doClose(); }
}
return new ProxyPreparedStatement((PreparedStatement) innerStmt );
}
else
{
class ProxyStatement extends FilterStatement implements C3P0ProxyStatement
{
WrapperStatementHelper wsh;
ProxyStatement(Statement s)
{
super( s );
this.wsh = new WrapperStatementHelper(this, s);
}
public Connection getConnection()
{ return parentConnection; }
public ResultSet getResultSet() throws SQLException
{ return wsh.wrap( super.getResultSet() ); }
public ResultSet getGeneratedKeys() throws SQLException
{ return wsh.wrap( super.getGeneratedKeys() ); }
public ResultSet executeQuery(String sql) throws SQLException
{ return wsh.wrap( super.executeQuery(sql) ); }
public Object rawStatementOperation(Method m, Object target, Object[] args)
throws IllegalAccessException, InvocationTargetException, SQLException
{ return wsh.doRawStatementOperation( m, target, args); }
public void close() throws SQLException
{ wsh.doClose(); }
}
return new ProxyStatement( innerStmt );
}
}
final class ProxyConnectionInvocationHandler implements InvocationHandler
{
Connection activeConnection = physicalConnection;
DatabaseMetaData metaData = null;
boolean connection_error_signaled = false;
final Set activeMetaDataResultSets = new HashSet();
Set doRawResultSets = null;
boolean txn_known_resolved = true;
public String toString()
{ return "C3P0ProxyConnection [Invocation Handler: " + super.toString() + ']'; }
private Object doRawConnectionOperation(Method m, Object target, Object[] args)
throws IllegalAccessException, InvocationTargetException, SQLException, Exception
{
if (activeConnection == null)
throw new SQLException("Connection previously closed. You cannot operate on a closed Connection.");
if (target == C3P0ProxyConnection.RAW_CONNECTION)
target = activeConnection;
for (int i = 0, len = args.length; i < len; ++i)
if (args[i] == C3P0ProxyConnection.RAW_CONNECTION)
args[i] = activeConnection;
Object out = m.invoke(target, args);
if (out instanceof Statement)
out = createProxyStatement( false, (Statement) out );
else if (out instanceof ResultSet)
{
if (doRawResultSets == null)
doRawResultSets = new HashSet();
out = new NullStatementSetManagedResultSet( (ResultSet) out, doRawResultSets );
}
return out;
}
public synchronized Object invoke(Object proxy, Method m, Object[] args)
throws Throwable
{
if ( OBJECT_METHODS.contains( m ) )
return m.invoke( this, args );
try
{
String mname = m.getName();
if (activeConnection != null)
{
if (mname.equals("rawConnectionOperation"))
{
ensureOkay();
txn_known_resolved = false;
return doRawConnectionOperation((Method) args[0], args[1], (Object[]) args[2]);
}
else if (mname.equals("setTransactionIsolation"))
{
ensureOkay();
m.invoke( activeConnection, args );
int lvl = ((Integer) args[0]).intValue();
isolation_lvl_nondefault = (lvl != dflt_txn_isolation);
return null;
}
else if (mname.equals("setCatalog"))
{
ensureOkay();
m.invoke( activeConnection, args );
String catalog = (String) args[0];
catalog_nondefault = ObjectUtils.eqOrBothNull(catalog, dflt_catalog);
return null;
}
else if (mname.equals("setHoldability"))
{
ensureOkay();
m.invoke( activeConnection, args );
int holdability = ((Integer) args[0]).intValue();
holdability_nondefault = (holdability != dflt_holdability);
return null;
}
else if (mname.equals("createStatement"))
{
ensureOkay();
txn_known_resolved = false;
Object stmt = m.invoke( activeConnection, args );
return createProxyStatement( (Statement) stmt );
}
else if (mname.equals("prepareStatement"))
{
ensureOkay();
txn_known_resolved = false;
Object pstmt;
if (scache == null)
{
pstmt = m.invoke( activeConnection, args );
return createProxyStatement( (Statement) pstmt );
}
else
{
pstmt = scache.checkoutStatement( physicalConnection,
m,
args );
return createProxyStatement( true,
(Statement) pstmt );
}
}
else if (mname.equals("prepareCall"))
{
ensureOkay();
txn_known_resolved = false;
Object cstmt;
if (scache == null)
{
cstmt = m.invoke( activeConnection, args );
return createProxyStatement( (Statement) cstmt );
}
else
{
cstmt = scache.checkoutStatement( physicalConnection, m, args );
return createProxyStatement( true,
(Statement) cstmt );
}
}
else if (mname.equals("getMetaData"))
{
ensureOkay();
txn_known_resolved = false;
DatabaseMetaData innerMd = activeConnection.getMetaData();
if (metaData == null)
{
synchronized (C3P0PooledConnection.this)
{ metaData = new SetManagedDatabaseMetaData(innerMd, activeMetaDataResultSets, exposedProxy); }
}
return metaData;
}
else if (mname.equals("silentClose"))
{
doSilentClose( proxy, ((Boolean) args[0]).booleanValue(), this.txn_known_resolved );
return null;
}
else if ( mname.equals("close") )
{
Exception e = doSilentClose( proxy, false, this.txn_known_resolved );
if (! connection_error_signaled)
ces.fireConnectionClosed();
if (e != null)
{
throw e;
}
else
return null;
}
else
{
ensureOkay();
txn_known_resolved = false;
return m.invoke( activeConnection, args );
}
}
else
{
if (mname.equals("close") ||
mname.equals("silentClose"))
return null;
else if (mname.equals("isClosed"))
return Boolean.TRUE;
else
{
throw new SQLException("You can't operate on " +
"a closed connection!!!");
}
}
}
catch (InvocationTargetException e)
{
Throwable convertMe = e.getTargetException();
SQLException sqle = handleMaybeFatalToPooledConnection( convertMe, proxy, false );
sqle.fillInStackTrace();
throw sqle;
}
}
private Exception doSilentClose(Object proxyConnection, boolean pooled_connection_is_dead)
{ return doSilentClose( proxyConnection, pooled_connection_is_dead, false ); }
private Exception doSilentClose(Object proxyConnection, boolean pooled_connection_is_dead, boolean known_resolved_txn)
{
if ( activeConnection != null )
{
synchronized ( C3P0PooledConnection.this )
{
if ( C3P0PooledConnection.this.exposedProxy == proxyConnection )
{
C3P0PooledConnection.this.exposedProxy = null;
}
else
logger.warning("(c3p0 issue) doSilentClose( ... ) called on a proxyConnection " +
"other than the current exposed proxy for its PooledConnection. [exposedProxy: " +
exposedProxy + ", proxyConnection: " + proxyConnection);
}
Exception out = null;
Exception exc1 = null, exc2 = null, exc3 = null, exc4 = null;
try
{
if (! pooled_connection_is_dead)
C3P0PooledConnection.this.reset(known_resolved_txn);
}
catch (Exception e)
{
exc1 = e;
}
exc2 = cleanupUncachedActiveStatements();
String errSource;
if (doRawResultSets != null)
{
activeMetaDataResultSets.addAll( doRawResultSets );
errSource = "DataBaseMetaData or raw Connection operation";
}
else
errSource = "DataBaseMetaData";
if (!closeAndRemoveResultSets( activeMetaDataResultSets ))
exc3 = new SQLException("Failed to close some " + errSource + " Result Sets.");
if (scache != null)
{
try
{ scache.checkinAll( physicalConnection ); }
catch ( Exception e )
{ exc4 = e; }
}
if (exc1 != null)
{
handleMaybeFatalToPooledConnection( exc1, proxyConnection, true );
out = exc1;
}
else if (exc2 != null)
{
handleMaybeFatalToPooledConnection( exc2, proxyConnection, true );
out = exc2;
}
else if (exc3 != null)
{
handleMaybeFatalToPooledConnection( exc3, proxyConnection, true );
out = exc3;
}
else if (exc4 != null)
{
handleMaybeFatalToPooledConnection( exc4, proxyConnection, true );
out = exc4;
}
activeConnection = null;
return out;
}
else
return null;
}
private SQLException handleMaybeFatalToPooledConnection( Throwable t, Object proxyConnection, boolean already_closed )
{
SQLException sqle = SqlUtils.toSQLException( t );
int status = connectionTester.statusOnException( physicalConnection, sqle );
updateConnectionStatus( status );
if (status != ConnectionTester.CONNECTION_IS_OKAY)
{
if (Debug.DEBUG)
{
logger.log(MLevel.INFO,
C3P0PooledConnection.this + " will no longer be pooled because it has been marked invalid by an Exception.",
t );
}
invalidatingException = sqle;
if (! connection_error_signaled)
{
ces.fireConnectionErrorOccurred( sqle );
connection_error_signaled = true;
}
}
return sqle;
}
}
interface ProxyConnection extends C3P0ProxyConnection
{ void silentClose( boolean known_invalid ) throws SQLException; }
public synchronized int getConnectionStatus()
{ return this.connection_status; }
private synchronized void updateConnectionStatus(int status)
{
switch ( this.connection_status )
{
case ConnectionTester.DATABASE_IS_INVALID:
break;
case ConnectionTester.CONNECTION_IS_INVALID:
if (status == ConnectionTester.DATABASE_IS_INVALID)
doBadUpdate(status);
break;
case ConnectionTester.CONNECTION_IS_OKAY:
if (status != ConnectionTester.CONNECTION_IS_OKAY)
doBadUpdate(status);
break;
default:
throw new InternalError(this + " -- Illegal Connection Status: " + this.connection_status);
}
}
private void doBadUpdate(int new_status)
{
this.connection_status = new_status;
try { this.close( true ); }
catch (SQLException e)
{
logger.log(MLevel.WARNING, "Broken Connection Close Error. ", e);
}
}
}