package org.infinispan.persistence.jdbc.connectionfactory;
import java.sql.Connection;
import java.sql.SQLException;
import org.infinispan.persistence.jdbc.JdbcUtil;
import org.infinispan.persistence.jdbc.configuration.ConnectionFactoryConfiguration;
import org.infinispan.persistence.jdbc.configuration.PooledConnectionFactoryConfiguration;
import org.infinispan.persistence.jdbc.logging.Log;
import org.infinispan.persistence.spi.PersistenceException;
import org.infinispan.util.logging.LogFactory;
/**
* Pooled connection factory that uses HikariCP by default. In order to utilise the legacy connection pool, C3P0, users
* must pass the system property <tt>infinispan.jdbc.c3p0.force</tt> with the value true.
*
* HikariCP property files can be specified by explicitly stating its path or name (if the file is on the classpath) via
* PooledConnectionFactoryConfiguration.propertyFile field. Or by ensuring that a <tt>hikari.properties</tt> file is
* on the classpath. Note, that the file specified by <tt>propertyField</tt> takes precedence over <tt>hikari.properties</tt>.
*
* For a complete configuration reference for C3P0 look <a href="http://www.mchange.com/projects/c3p0/index.html#configuration">here</a>.
* The connection pool can be configured n various ways, as described
* <a href="http://www.mchange.com/projects/c3p0/index.html#configuration_files">here</a>. The simplest way is by having
* an <tt>c3p0.properties</tt> file in the classpath.
*
* If no properties files are found for either HikariCP or C3PO then the default values of these connection pools are
* utilised.
*
* @author Mircea.Markus@jboss.com
* @author Tristan Tarrant
* @author Ryan Emerson
*/
public class PooledConnectionFactory extends ConnectionFactory {
private static final Log log = LogFactory.getLog(PooledConnectionFactory.class, Log.class);
private static boolean trace = log.isTraceEnabled();
private ConnectionPool connectionPool;
@Override
public void start(ConnectionFactoryConfiguration config, ClassLoader classLoader) throws PersistenceException {
PooledConnectionFactoryConfiguration poolConfig;
if (config instanceof PooledConnectionFactoryConfiguration) {
poolConfig = (PooledConnectionFactoryConfiguration) config;
} else {
throw new PersistenceException("ConnectionFactoryConfiguration passed in must be an instance of " +
"PooledConnectionFactoryConfiguration");
}
connectionPool = C3P0ConnectionPool.forceC3P0() ? new C3P0ConnectionPool(classLoader, poolConfig) :
new HikariConnectionPool(classLoader, poolConfig);
if (trace) log.tracef("Started connection factory with config: %s", config);
}
@Override
public void stop() {
if (connectionPool != null) {
connectionPool.close();
if (trace) log.debug("Successfully stopped PooledConnectionFactory.");
}
}
@Override
public Connection getConnection() throws PersistenceException {
try {
logBefore(true);
Connection connection = connectionPool.getConnection();
logAfter(connection, true);
return connection;
} catch (SQLException e) {
throw new PersistenceException("Failed obtaining connection from PooledDataSource", e);
}
}
@Override
public void releaseConnection(Connection conn) {
logBefore(false);
JdbcUtil.safeClose(conn);
logAfter(conn, false);
}
public int getMaxPoolSize() {
return connectionPool.getMaxPoolSize();
}
public int getNumConnectionsAllUsers() throws SQLException {
return connectionPool.getNumConnectionsAllUsers();
}
public int getNumBusyConnectionsAllUsers() throws SQLException {
return connectionPool.getNumBusyConnectionsAllUsers();
}
private void logBefore(boolean checkout) {
log(null, checkout, true);
}
private void logAfter(Connection connection, boolean checkout) {
log(connection, checkout, false);
}
private void log(Connection connection, boolean checkout, boolean before) {
if (trace) {
String stage = before ? "before" : "after";
String operation = checkout ? "checkout" : "release";
try {
log.tracef("DataSource %s %s (NumBusyConnectionsAllUsers) : %d, (NumConnectionsAllUsers) : %d",
stage, operation, getNumBusyConnectionsAllUsers(), getNumConnectionsAllUsers());
} catch (SQLException e) {
log.sqlFailureUnexpected(e);
}
if (connection != null)
log.tracef("Connection %s : %s", operation, connection);
}
}
}