Reformatting with new Eclipse formatter settings. Went with a variation of Sun-style, which leads to more compact method bodies, but still white-space to "highlight" class and method declarations.

pull/131/head
Brett Wooldridge 11 years ago
parent 0486c5904e
commit 775cba7db5

File diff suppressed because it is too large Load Diff

@ -23,123 +23,123 @@ package com.zaxxer.hikari;
*/
public interface HikariConfigMBean
{
/**
* Get the maximum number of milliseconds that a client will wait for a connection from the pool. If this
* time is exceeded without a connection becoming available, a SQLException will be thrown from
* {@link javax.sql.DataSource#getConnection()}.
*
* @return the connection timeout in milliseconds
*/
long getConnectionTimeout();
/**
* Get the maximum number of milliseconds that a client will wait for a connection from the pool. If this
* time is exceeded without a connection becoming available, a SQLException will be thrown from
* {@link javax.sql.DataSource#getConnection()}.
*
* @return the connection timeout in milliseconds
*/
long getConnectionTimeout();
/**
* Set the maximum number of milliseconds that a client will wait for a connection from the pool. If this
* time is exceeded without a connection becoming available, a SQLException will be thrown from
* {@link javax.sql.DataSource#getConnection()}.
*
* @param connectionTimeoutMs the connection timeout in milliseconds
*/
void setConnectionTimeout(long connectionTimeoutMs);
/**
* Set the maximum number of milliseconds that a client will wait for a connection from the pool. If this
* time is exceeded without a connection becoming available, a SQLException will be thrown from
* {@link javax.sql.DataSource#getConnection()}.
*
* @param connectionTimeoutMs the connection timeout in milliseconds
*/
void setConnectionTimeout(long connectionTimeoutMs);
/**
* This property controls the maximum amount of time (in milliseconds) that a connection is allowed to sit
* idle in the pool. Whether a connection is retired as idle or not is subject to a maximum variation of +30
* seconds, and average variation of +15 seconds. A connection will never be retired as idle before this timeout.
* A value of 0 means that idle connections are never removed from the pool.
*
* @return the idle timeout in milliseconds
*/
long getIdleTimeout();
/**
* This property controls the maximum amount of time (in milliseconds) that a connection is allowed to sit
* idle in the pool. Whether a connection is retired as idle or not is subject to a maximum variation of +30
* seconds, and average variation of +15 seconds. A connection will never be retired as idle before this timeout.
* A value of 0 means that idle connections are never removed from the pool.
*
* @return the idle timeout in milliseconds
*/
long getIdleTimeout();
/**
* This property controls the maximum amount of time (in milliseconds) that a connection is allowed to sit
* idle in the pool. Whether a connection is retired as idle or not is subject to a maximum variation of +30
* seconds, and average variation of +15 seconds. A connection will never be retired as idle before this timeout.
* A value of 0 means that idle connections are never removed from the pool.
*
* @param idleTimeoutMs the idle timeout in milliseconds
*/
void setIdleTimeout(long idleTimeoutMs);
/**
* This property controls the maximum amount of time (in milliseconds) that a connection is allowed to sit
* idle in the pool. Whether a connection is retired as idle or not is subject to a maximum variation of +30
* seconds, and average variation of +15 seconds. A connection will never be retired as idle before this timeout.
* A value of 0 means that idle connections are never removed from the pool.
*
* @param idleTimeoutMs the idle timeout in milliseconds
*/
void setIdleTimeout(long idleTimeoutMs);
/**
* This property controls the amount of time that a connection can be out of the pool before a message is
* logged indicating a possible connection leak. A value of 0 means leak detection is disabled.
*
* @return the connection leak detection threshold in milliseconds
*/
long getLeakDetectionThreshold();
/**
* This property controls the amount of time that a connection can be out of the pool before a message is
* logged indicating a possible connection leak. A value of 0 means leak detection is disabled.
*
* @return the connection leak detection threshold in milliseconds
*/
long getLeakDetectionThreshold();
/**
* This property controls the amount of time that a connection can be out of the pool before a message is
* logged indicating a possible connection leak. A value of 0 means leak detection is disabled.
*
* @param leakDetectionThresholdMs the connection leak detection threshold in milliseconds
*/
void setLeakDetectionThreshold(long leakDetectionThresholdMs);
/**
* This property controls the amount of time that a connection can be out of the pool before a message is
* logged indicating a possible connection leak. A value of 0 means leak detection is disabled.
*
* @param leakDetectionThresholdMs the connection leak detection threshold in milliseconds
*/
void setLeakDetectionThreshold(long leakDetectionThresholdMs);
/**
* This property controls the maximum lifetime of a connection in the pool. When a connection reaches this
* timeout, even if recently used, it will be retired from the pool. An in-use connection will never be
* retired, only when it is idle will it be removed.
*
* @return the maximum connection lifetime in milliseconds
*/
long getMaxLifetime();
/**
* This property controls the maximum lifetime of a connection in the pool. When a connection reaches this
* timeout, even if recently used, it will be retired from the pool. An in-use connection will never be
* retired, only when it is idle will it be removed.
*
* @return the maximum connection lifetime in milliseconds
*/
long getMaxLifetime();
/**
* This property controls the maximum lifetime of a connection in the pool. When a connection reaches this
* timeout, even if recently used, it will be retired from the pool. An in-use connection will never be
* retired, only when it is idle will it be removed.
*
* @param maxLifetimeMs the maximum connection lifetime in milliseconds
*/
void setMaxLifetime(long maxLifetimeMs);
/**
* This property controls the maximum lifetime of a connection in the pool. When a connection reaches this
* timeout, even if recently used, it will be retired from the pool. An in-use connection will never be
* retired, only when it is idle will it be removed.
*
* @param maxLifetimeMs the maximum connection lifetime in milliseconds
*/
void setMaxLifetime(long maxLifetimeMs);
/**
* The property controls the maximum size that the pool is allowed to reach, including both idle and in-use
* connections. Basically this value will determine the maximum number of actual connections to the database
* backend.
* <p>
* When the pool reaches this size, and no idle connections are available, calls to getConnection() will
* block for up to connectionTimeout milliseconds before timing out.
*
* @return the minimum number of connections in the pool
*/
int getMinimumIdle();
/**
* The property controls the maximum size that the pool is allowed to reach, including both idle and in-use
* connections. Basically this value will determine the maximum number of actual connections to the database
* backend.
* <p>
* When the pool reaches this size, and no idle connections are available, calls to getConnection() will
* block for up to connectionTimeout milliseconds before timing out.
*
* @return the minimum number of connections in the pool
*/
int getMinimumIdle();
/**
* The property controls the minimum number of idle connections that HikariCP tries to maintain in the pool,
* including both idle and in-use connections. If the idle connections dip below this value, HikariCP will
* make a best effort to restore them quickly and efficiently.
*
* @param minIdle the minimum number of idle connections in the pool to maintain
*/
void setMinimumIdle(int minIdle);
/**
* The property controls the minimum number of idle connections that HikariCP tries to maintain in the pool,
* including both idle and in-use connections. If the idle connections dip below this value, HikariCP will
* make a best effort to restore them quickly and efficiently.
*
* @param minIdle the minimum number of idle connections in the pool to maintain
*/
void setMinimumIdle(int minIdle);
/**
* The property controls the maximum number of connections that HikariCP will keep in the pool,
* including both idle and in-use connections.
*
* @return the maximum number of connections in the pool
*/
int getMaximumPoolSize();
/**
* The property controls the maximum number of connections that HikariCP will keep in the pool,
* including both idle and in-use connections.
*
* @return the maximum number of connections in the pool
*/
int getMaximumPoolSize();
/**
* The property controls the maximum size that the pool is allowed to reach, including both idle and in-use
* connections. Basically this value will determine the maximum number of actual connections to the database
* backend.
* <p>
* When the pool reaches this size, and no idle connections are available, calls to getConnection() will
* block for up to connectionTimeout milliseconds before timing out.
*
* @param maxPoolSize the maximum number of connections in the pool
*/
void setMaximumPoolSize(int maxPoolSize);
/**
* The property controls the maximum size that the pool is allowed to reach, including both idle and in-use
* connections. Basically this value will determine the maximum number of actual connections to the database
* backend.
* <p>
* When the pool reaches this size, and no idle connections are available, calls to getConnection() will
* block for up to connectionTimeout milliseconds before timing out.
*
* @param maxPoolSize the maximum number of connections in the pool
*/
void setMaximumPoolSize(int maxPoolSize);
/**
* The name of the connection pool.
*
* @return the name of the connection pool
*/
String getPoolName();
/**
* The name of the connection pool.
*
* @return the name of the connection pool
*/
String getPoolName();
}

@ -38,272 +38,251 @@ import com.zaxxer.hikari.util.DriverDataSource;
*/
public class HikariDataSource extends HikariConfig implements DataSource
{
private static final Logger LOGGER = LoggerFactory.getLogger(HikariDataSource.class);
// We use a concrete HashMap rather than Map to avoid an invokeinterface callsite
private final HashMap<MultiPoolKey, HikariPool> multiPool;
private volatile boolean isShutdown;
private int loginTimeout;
/* Package scopped for testing */
private final HikariPool fastPathPool;
private volatile HikariPool pool;
/**
* Default constructor. Setters be used to configure the pool. Using
* this constructor vs. {@link #HikariDataSource(HikariConfig)} will
* result in {@link #getConnection()} performance that is slightly lower
* due to lazy initialization checks.
*/
public HikariDataSource()
{
super();
fastPathPool = null;
multiPool = new HashMap<MultiPoolKey, HikariPool>();
}
/**
* Construct a HikariDataSource with the specified configuration.
*
* @param configuration a HikariConfig instance
*/
public HikariDataSource(HikariConfig configuration)
{
configuration.validate();
configuration.copyState(this);
multiPool = new HashMap<MultiPoolKey, HikariPool>();
LOGGER.info("HikariCP pool {} is starting.", configuration.getPoolName());
pool = fastPathPool = new HikariPool(this);
multiPool.put(new MultiPoolKey(getUsername(), getPassword()), pool);
}
/** {@inheritDoc} */
@Override
public Connection getConnection() throws SQLException
{
if (isShutdown)
{
throw new SQLException("Pool has been shutdown");
}
if (fastPathPool != null)
{
return fastPathPool.getConnection();
}
// See http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java
HikariPool result = pool;
if (result == null)
{
synchronized (this)
{
result = pool;
if (result == null)
{
validate();
LOGGER.info("HikariCP pool {} is starting.", getPoolName());
pool = result = new HikariPool(this);
multiPool.put(new MultiPoolKey(getUsername(), getPassword()), pool);
}
private static final Logger LOGGER = LoggerFactory.getLogger(HikariDataSource.class);
// We use a concrete HashMap rather than Map to avoid an invokeinterface callsite
private final HashMap<MultiPoolKey, HikariPool> multiPool;
private volatile boolean isShutdown;
private int loginTimeout;
/* Package scopped for testing */
private final HikariPool fastPathPool;
private volatile HikariPool pool;
/**
* Default constructor. Setters be used to configure the pool. Using
* this constructor vs. {@link #HikariDataSource(HikariConfig)} will
* result in {@link #getConnection()} performance that is slightly lower
* due to lazy initialization checks.
*/
public HikariDataSource()
{
super();
fastPathPool = null;
multiPool = new HashMap<MultiPoolKey, HikariPool>();
}
/**
* Construct a HikariDataSource with the specified configuration.
*
* @param configuration a HikariConfig instance
*/
public HikariDataSource(HikariConfig configuration)
{
configuration.validate();
configuration.copyState(this);
multiPool = new HashMap<MultiPoolKey, HikariPool>();
LOGGER.info("HikariCP pool {} is starting.", configuration.getPoolName());
pool = fastPathPool = new HikariPool(this);
multiPool.put(new MultiPoolKey(getUsername(), getPassword()), pool);
}
/** {@inheritDoc} */
@Override
public Connection getConnection() throws SQLException
{
if (isShutdown) {
throw new SQLException("Pool has been shutdown");
}
if (fastPathPool != null) {
return fastPathPool.getConnection();
}
// See http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java
HikariPool result = pool;
if (result == null) {
synchronized (this) {
result = pool;
if (result == null) {
validate();
LOGGER.info("HikariCP pool {} is starting.", getPoolName());
pool = result = new HikariPool(this);
multiPool.put(new MultiPoolKey(getUsername(), getPassword()), pool);
}
}
return result.getConnection();
}
/** {@inheritDoc} */
@Override
public Connection getConnection(String username, String password) throws SQLException
{
if (isShutdown)
{
throw new SQLException("Pool has been shutdown");
}
final MultiPoolKey key = new MultiPoolKey(username, password);
HikariPool hikariPool;
synchronized (multiPool)
{
hikariPool = multiPool.get(key);
if (hikariPool == null)
{
hikariPool = new HikariPool(this, username, password);
multiPool.put(key, hikariPool);
}
}
return hikariPool.getConnection();
}
/** {@inheritDoc} */
@Override
public PrintWriter getLogWriter() throws SQLException
{
return (pool.getDataSource() != null ? pool.getDataSource().getLogWriter() : null);
}
/** {@inheritDoc} */
@Override
public void setLogWriter(PrintWriter out) throws SQLException
{
if (pool.getDataSource() != null)
{
pool.getDataSource().setLogWriter(out);
}
}
/** {@inheritDoc} */
@Override
public void setLoginTimeout(int seconds) throws SQLException
{
this.loginTimeout = seconds;
}
/** {@inheritDoc} */
@Override
public int getLoginTimeout() throws SQLException
{
return loginTimeout;
}
/** {@inheritDoc} */
public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException
{
throw new SQLFeatureNotSupportedException();
}
/** {@inheritDoc} */
@Override
@SuppressWarnings("unchecked")
public <T> T unwrap(Class<T> iface) throws SQLException
{
if (pool != null && iface.isInstance(pool.getDataSource()))
{
return (T) pool.getDataSource();
}
throw new SQLException("Wrapped connection is not an instance of " + iface);
}
/** {@inheritDoc} */
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException
{
return (pool != null && pool.getDataSource().getClass().isAssignableFrom(iface));
}
/**
* Evict a connection from the pool. Use caution using this method, if you
* evict the same connection more than one time, the internal pool accounting
* will become invalid and the pool may stop functioning.
*
* @param connection the connection to evict from the pool
*/
public void evictConnection(Connection connection)
{
if (!isShutdown && pool != null && connection instanceof IHikariConnectionProxy)
{
pool.closeConnection((IHikariConnectionProxy) connection);
}
}
/**
* <code>close()</code> and <code>shutdown()</code> are synonymous.
*/
public void close()
{
shutdown();
}
/**
* Shutdown the DataSource and its associated pool.
*/
public void shutdown()
{
if (isShutdown)
{
return;
}
isShutdown = true;
if (fastPathPool != null)
{
shutdownHelper(fastPathPool);
}
for (HikariPool hikariPool : multiPool.values())
{
shutdownHelper(hikariPool);
}
}
/** {@inheritDoc} */
@Override
public String toString()
{
return String.format("HikariDataSource (%s)", pool);
}
private void shutdownHelper(HikariPool hPool)
{
try
{
hPool.shutdown();
}
catch (InterruptedException e)
{
LoggerFactory.getLogger(getClass()).warn("Interrupted during shutdown", e);
}
if (hPool.getDataSource() instanceof DriverDataSource)
{
((DriverDataSource) hPool.getDataSource()).shutdown();
}
}
private static class MultiPoolKey
{
private String username;
private String password;
MultiPoolKey(String username, String password)
{
this.username = username;
this.password = password;
}
@Override
public int hashCode()
{
return (password == null ? 0 : password.hashCode());
}
@Override
public boolean equals(Object obj)
{
MultiPoolKey otherKey = ((MultiPoolKey) obj);
if (username != null && !username.equals(otherKey.username))
{
return false;
}
else if (username != otherKey.username)
{
return false;
}
else if (password != null && !password.equals(otherKey.password))
{
return false;
}
else if (password != otherKey.password)
{
return false;
}
return true;
}
}
}
}
return result.getConnection();
}
/** {@inheritDoc} */
@Override
public Connection getConnection(String username, String password) throws SQLException
{
if (isShutdown) {
throw new SQLException("Pool has been shutdown");
}
final MultiPoolKey key = new MultiPoolKey(username, password);
HikariPool hikariPool;
synchronized (multiPool) {
hikariPool = multiPool.get(key);
if (hikariPool == null) {
hikariPool = new HikariPool(this, username, password);
multiPool.put(key, hikariPool);
}
}
return hikariPool.getConnection();
}
/** {@inheritDoc} */
@Override
public PrintWriter getLogWriter() throws SQLException
{
return (pool.getDataSource() != null ? pool.getDataSource().getLogWriter() : null);
}
/** {@inheritDoc} */
@Override
public void setLogWriter(PrintWriter out) throws SQLException
{
if (pool.getDataSource() != null) {
pool.getDataSource().setLogWriter(out);
}
}
/** {@inheritDoc} */
@Override
public void setLoginTimeout(int seconds) throws SQLException
{
this.loginTimeout = seconds;
}
/** {@inheritDoc} */
@Override
public int getLoginTimeout() throws SQLException
{
return loginTimeout;
}
/** {@inheritDoc} */
public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException
{
throw new SQLFeatureNotSupportedException();
}
/** {@inheritDoc} */
@Override
@SuppressWarnings("unchecked")
public <T> T unwrap(Class<T> iface) throws SQLException
{
if (pool != null && iface.isInstance(pool.getDataSource())) {
return (T) pool.getDataSource();
}
throw new SQLException("Wrapped connection is not an instance of " + iface);
}
/** {@inheritDoc} */
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException
{
return (pool != null && pool.getDataSource().getClass().isAssignableFrom(iface));
}
/**
* Evict a connection from the pool. Use caution using this method, if you
* evict the same connection more than one time, the internal pool accounting
* will become invalid and the pool may stop functioning.
*
* @param connection the connection to evict from the pool
*/
public void evictConnection(Connection connection)
{
if (!isShutdown && pool != null && connection instanceof IHikariConnectionProxy) {
pool.closeConnection((IHikariConnectionProxy) connection);
}
}
/**
* <code>close()</code> and <code>shutdown()</code> are synonymous.
*/
public void close()
{
shutdown();
}
/**
* Shutdown the DataSource and its associated pool.
*/
public void shutdown()
{
if (isShutdown) {
return;
}
isShutdown = true;
if (fastPathPool != null) {
shutdownHelper(fastPathPool);
}
for (HikariPool hikariPool : multiPool.values()) {
shutdownHelper(hikariPool);
}
}
/** {@inheritDoc} */
@Override
public String toString()
{
return String.format("HikariDataSource (%s)", pool);
}
private void shutdownHelper(HikariPool hPool)
{
try {
hPool.shutdown();
}
catch (InterruptedException e) {
LoggerFactory.getLogger(getClass()).warn("Interrupted during shutdown", e);
}
if (hPool.getDataSource() instanceof DriverDataSource) {
((DriverDataSource) hPool.getDataSource()).shutdown();
}
}
private static class MultiPoolKey
{
private String username;
private String password;
MultiPoolKey(String username, String password)
{
this.username = username;
this.password = password;
}
@Override
public int hashCode()
{
return (password == null ? 0 : password.hashCode());
}
@Override
public boolean equals(Object obj)
{
MultiPoolKey otherKey = ((MultiPoolKey) obj);
if (username != null && !username.equals(otherKey.username)) {
return false;
}
else if (username != otherKey.username) {
return false;
}
else if (password != null && !password.equals(otherKey.password)) {
return false;
}
else if (password != otherKey.password) {
return false;
}
return true;
}
}
}

@ -37,85 +37,72 @@ import com.zaxxer.hikari.util.PropertyBeanSetter;
*/
public class HikariJNDIFactory implements ObjectFactory
{
@Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception
{
// We only know how to deal with <code>javax.naming.Reference</code> that specify a class name of "javax.sql.DataSource"
if ((obj == null) || !(obj instanceof Reference))
{
return null;
}
@Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception
{
// We only know how to deal with <code>javax.naming.Reference</code> that specify a class name of "javax.sql.DataSource"
if ((obj == null) || !(obj instanceof Reference)) {
return null;
}
Reference ref = (Reference) obj;
if (!"javax.sql.DataSource".equals(ref.getClassName()))
{
throw new NamingException(ref.getClassName() + " is not a valid class name/type for this JNDI factory.");
}
Reference ref = (Reference) obj;
if (!"javax.sql.DataSource".equals(ref.getClassName())) {
throw new NamingException(ref.getClassName() + " is not a valid class name/type for this JNDI factory.");
}
Properties properties = new Properties();
for (String propertyName : PropertyBeanSetter.getPropertyNames(HikariConfig.class))
{
RefAddr ra = ref.get(propertyName);
if (ra != null)
{
String propertyValue = ra.getContent().toString();
properties.setProperty(propertyName, propertyValue);
}
}
Properties properties = new Properties();
for (String propertyName : PropertyBeanSetter.getPropertyNames(HikariConfig.class)) {
RefAddr ra = ref.get(propertyName);
if (ra != null) {
String propertyValue = ra.getContent().toString();
properties.setProperty(propertyName, propertyValue);
}
}
return createDataSource(properties, nameCtx);
}
return createDataSource(properties, nameCtx);
}
private DataSource createDataSource(Properties properties, Context context)
{
if (properties.getProperty("dataSourceJNDI") != null)
{
return lookupJndiDataSource(properties, context);
}
private DataSource createDataSource(Properties properties, Context context)
{
if (properties.getProperty("dataSourceJNDI") != null) {
return lookupJndiDataSource(properties, context);
}
return new HikariDataSource(new HikariConfig(properties));
}
return new HikariDataSource(new HikariConfig(properties));
}
private DataSource lookupJndiDataSource(Properties properties, Context context)
{
DataSource jndiDS = null;
String jndiName = properties.getProperty("dataSourceJNDI");
try
{
if (context != null)
{
jndiDS = (DataSource) context.lookup(jndiName);
}
else
{
throw new RuntimeException("dataSourceJNDI property is configued, but local JNDI context is null.");
}
}
catch (NamingException e)
{
throw new RuntimeException("The name \"" + jndiName + "\" can not be found in the local context.");
}
private DataSource lookupJndiDataSource(Properties properties, Context context)
{
DataSource jndiDS = null;
String jndiName = properties.getProperty("dataSourceJNDI");
try {
if (context != null) {
jndiDS = (DataSource) context.lookup(jndiName);
}
else {
throw new RuntimeException("dataSourceJNDI property is configued, but local JNDI context is null.");
}
}
catch (NamingException e) {
throw new RuntimeException("The name \"" + jndiName + "\" can not be found in the local context.");
}
if (jndiDS == null)
{
try
{
context = (Context) (new InitialContext());
jndiDS = (DataSource) context.lookup(jndiName);
}
catch (NamingException e)
{
throw new RuntimeException("The name \"" + jndiName + "\" can not be found in the InitialContext.");
}
}
if (jndiDS == null) {
try {
context = (Context) (new InitialContext());
jndiDS = (DataSource) context.lookup(jndiName);
}
catch (NamingException e) {
throw new RuntimeException("The name \"" + jndiName + "\" can not be found in the InitialContext.");
}
}
if (jndiDS != null)
{
HikariConfig config = new HikariConfig(properties);
config.setDataSource(jndiDS);
return new HikariDataSource(config);
}
if (jndiDS != null) {
HikariConfig config = new HikariConfig(properties);
config.setDataSource(jndiDS);
return new HikariDataSource(config);
}
return null;
}
return null;
}
}

@ -29,13 +29,13 @@ import java.sql.SQLException;
*/
public interface IConnectionCustomizer
{
/**
* The Connection object that is passed into this method is the "raw"
* Connection instance provided by the JDBC driver, not a wrapped
* HikariCP connection.
*
* @param connection a native JDBC driver Connection instance to customize
* @throws SQLException should be thrown if an error condition is encountered during customization
*/
void customize(Connection connection) throws SQLException;
/**
* The Connection object that is passed into this method is the "raw"
* Connection instance provided by the JDBC driver, not a wrapped
* HikariCP connection.
*
* @param connection a native JDBC driver Connection instance to customize
* @throws SQLException should be thrown if an error condition is encountered during customization
*/
void customize(Connection connection) throws SQLException;
}

@ -30,44 +30,41 @@ import com.zaxxer.hikari.HikariConfig;
*/
public class HikariConfigurationUtil
{
public static final String CONFIG_PREFIX = "hibernate.hikari.";
public static final String CONFIG_PREFIX_DATASOURCE = "hibernate.hikari.dataSource.";
public static final String CONFIG_PREFIX = "hibernate.hikari.";
public static final String CONFIG_PREFIX_DATASOURCE = "hibernate.hikari.dataSource.";
/**
* Create/load a HikariConfig from Hibernate properties.
*
* @param props a map of Hibernate properties
* @return a HikariConfig
*/
@SuppressWarnings("rawtypes")
public static HikariConfig loadConfiguration(Map props)
{
Properties hikariProps = new Properties();
copyProperty(AvailableSettings.ISOLATION, props, "transactionIsolation", hikariProps);
copyProperty(AvailableSettings.AUTOCOMMIT, props, "autoCommit", hikariProps);
copyProperty(AvailableSettings.DRIVER, props, "driverClassName", hikariProps);
copyProperty(AvailableSettings.URL, props, "jdbcUrl", hikariProps);
copyProperty(AvailableSettings.USER, props, "username", hikariProps);
copyProperty(AvailableSettings.PASS, props, "password", hikariProps);
/**
* Create/load a HikariConfig from Hibernate properties.
*
* @param props a map of Hibernate properties
* @return a HikariConfig
*/
@SuppressWarnings("rawtypes")
public static HikariConfig loadConfiguration(Map props)
{
Properties hikariProps = new Properties();
copyProperty(AvailableSettings.ISOLATION, props, "transactionIsolation", hikariProps);
copyProperty(AvailableSettings.AUTOCOMMIT, props, "autoCommit", hikariProps);
copyProperty(AvailableSettings.DRIVER, props, "driverClassName", hikariProps);
copyProperty(AvailableSettings.URL, props, "jdbcUrl", hikariProps);
copyProperty(AvailableSettings.USER, props, "username", hikariProps);
copyProperty(AvailableSettings.PASS, props, "password", hikariProps);
for (Object keyo : props.keySet())
{
String key = (String) keyo;
if (key.startsWith(CONFIG_PREFIX))
{
hikariProps.setProperty(key.substring(CONFIG_PREFIX.length()), (String) props.get(key));
}
}
for (Object keyo : props.keySet()) {
String key = (String) keyo;
if (key.startsWith(CONFIG_PREFIX)) {
hikariProps.setProperty(key.substring(CONFIG_PREFIX.length()), (String) props.get(key));
}
}
return new HikariConfig(hikariProps);
}
return new HikariConfig(hikariProps);
}
@SuppressWarnings("rawtypes")
private static void copyProperty(String srcKey, Map src, String dstKey, Properties dst)
{
if (src.containsKey(srcKey))
{
dst.setProperty(dstKey, (String) src.get(srcKey));
}
}
@SuppressWarnings("rawtypes")
private static void copyProperty(String srcKey, Map src, String dstKey, Properties dst)
{
if (src.containsKey(srcKey)) {
dst.setProperty(dstKey, (String) src.get(srcKey));
}
}
}

@ -38,113 +38,108 @@ import com.zaxxer.hikari.HikariDataSource;
*/
public class HikariConnectionProvider implements ConnectionProvider, Configurable, Stoppable
{
private static final long serialVersionUID = -9131625057941275711L;
private static final Logger LOGGER = LoggerFactory.getLogger(HikariConnectionProvider.class);
/**
* HikariCP configuration.
*/
private HikariConfig hcfg;
/**
* HikariCP data source.
*/
private HikariDataSource hds;
// *************************************************************************
//
// *************************************************************************
/**
* c-tor
*/
public HikariConnectionProvider()
{
this.hcfg = null;
this.hds = null;
}
// *************************************************************************
// Configurable
// *************************************************************************
@SuppressWarnings("rawtypes")
@Override
public void configure(Map props) throws HibernateException
{
try
{
LOGGER.debug("Configuring HikariCP");
this.hcfg = HikariConfigurationUtil.loadConfiguration(props);
this.hds = new HikariDataSource(this.hcfg);
}
catch (Exception e)
{
throw new HibernateException(e);
}
LOGGER.debug("HikariCP Configured");
}
// *************************************************************************
// ConnectionProvider
// *************************************************************************
@Override
public Connection getConnection() throws SQLException
{
Connection conn = null;
if (this.hds != null)
{
conn = this.hds.getConnection();
}
return conn;
}
@Override
public void closeConnection(Connection conn) throws SQLException
{
conn.close();
}
@Override
public boolean supportsAggressiveRelease()
{
return false;
}
@Override
@SuppressWarnings("rawtypes")
public boolean isUnwrappableAs(Class unwrapType)
{
return ConnectionProvider.class.equals(unwrapType) || HikariConnectionProvider.class.isAssignableFrom(unwrapType);
}
@Override
@SuppressWarnings("unchecked")
public <T> T unwrap(Class<T> unwrapType)
{
if (isUnwrappableAs(unwrapType))
{
return (T) this;
}
else
{
throw new UnknownUnwrapTypeException(unwrapType);
}
}
// *************************************************************************
// Stoppable
// *************************************************************************
@Override
public void stop()
{
this.hds.shutdown();
}
private static final long serialVersionUID = -9131625057941275711L;
private static final Logger LOGGER = LoggerFactory.getLogger(HikariConnectionProvider.class);
/**
* HikariCP configuration.
*/
private HikariConfig hcfg;
/**
* HikariCP data source.
*/
private HikariDataSource hds;
// *************************************************************************
//
// *************************************************************************
/**
* c-tor
*/
public HikariConnectionProvider()
{
this.hcfg = null;
this.hds = null;
}
// *************************************************************************
// Configurable
// *************************************************************************
@SuppressWarnings("rawtypes")
@Override
public void configure(Map props) throws HibernateException
{
try {
LOGGER.debug("Configuring HikariCP");
this.hcfg = HikariConfigurationUtil.loadConfiguration(props);
this.hds = new HikariDataSource(this.hcfg);
}
catch (Exception e) {
throw new HibernateException(e);
}
LOGGER.debug("HikariCP Configured");
}
// *************************************************************************
// ConnectionProvider
// *************************************************************************
@Override
public Connection getConnection() throws SQLException
{
Connection conn = null;
if (this.hds != null) {
conn = this.hds.getConnection();
}
return conn;
}
@Override
public void closeConnection(Connection conn) throws SQLException
{
conn.close();
}
@Override
public boolean supportsAggressiveRelease()
{
return false;
}
@Override
@SuppressWarnings("rawtypes")
public boolean isUnwrappableAs(Class unwrapType)
{
return ConnectionProvider.class.equals(unwrapType) || HikariConnectionProvider.class.isAssignableFrom(unwrapType);
}
@Override
@SuppressWarnings("unchecked")
public <T> T unwrap(Class<T> unwrapType)
{
if (isUnwrappableAs(unwrapType)) {
return (T) this;
}
else {
throw new UnknownUnwrapTypeException(unwrapType);
}
}
// *************************************************************************
// Stoppable
// *************************************************************************
@Override
public void stop()
{
this.hds.shutdown();
}
}

@ -23,44 +23,43 @@ import com.zaxxer.hikari.pool.HikariPool;
public final class CodaHaleMetricsTracker extends MetricsTracker
{
private MetricRegistry registry;
private Timer connectionObtainTimer;
private Histogram connectionUsage;
private MetricRegistry registry;
private Timer connectionObtainTimer;
private Histogram connectionUsage;
public CodaHaleMetricsTracker(String poolName)
{
registry = new MetricRegistry();
connectionObtainTimer = registry.timer(MetricRegistry.name(HikariPool.class, "connection", "wait"));
connectionUsage = registry.histogram(MetricRegistry.name(HikariPool.class, "connection", "usage"));
}
public CodaHaleMetricsTracker(String poolName)
{
registry = new MetricRegistry();
connectionObtainTimer = registry.timer(MetricRegistry.name(HikariPool.class, "connection", "wait"));
connectionUsage = registry.histogram(MetricRegistry.name(HikariPool.class, "connection", "usage"));
}
@Override
public Context recordConnectionRequest(long requestTime)
{
return new Context(connectionObtainTimer);
}
@Override
public Context recordConnectionRequest(long requestTime)
{
return new Context(connectionObtainTimer);
}
@Override
public void recordConnectionUsage(long usageMilleseconds)
{
connectionUsage.update(usageMilleseconds);
}
@Override
public void recordConnectionUsage(long usageMilleseconds)
{
connectionUsage.update(usageMilleseconds);
}
public static final class Context extends MetricsContext
{
Timer.Context innerContext;
public static final class Context extends MetricsContext
{
Timer.Context innerContext;
Context(Timer timer)
{
innerContext = timer.time();
}
Context(Timer timer)
{
innerContext = timer.time();
}
public void stop()
{
if (innerContext != null)
{
innerContext.stop();
}
}
}
public void stop()
{
if (innerContext != null) {
innerContext.stop();
}
}
}
}

@ -22,36 +22,36 @@ package com.zaxxer.hikari.metrics;
*/
public interface IMetricsTracker
{
/**
* This method is called when a connection request starts. The {@#MetricsContext.stop()}
* method will be called at the completion of the connection request, whether or not an
* exception occurred.
*
* @param startTime the timestamp of the start time as returned by System.currentTimeMillis()
* @return an instance of MetricsContext
*/
public MetricsContext recordConnectionRequest(long startTime);
/**
* This method is called when a connection request starts. The {@#MetricsContext.stop()}
* method will be called at the completion of the connection request, whether or not an
* exception occurred.
*
* @param startTime the timestamp of the start time as returned by System.currentTimeMillis()
* @return an instance of MetricsContext
*/
public MetricsContext recordConnectionRequest(long startTime);
/**
* This method is called when a Connection is closed, with the total time in milliseconds
* that the Connection was out of the pool.
*
* @param usageMilleseconds the Connection usage time in milliseconds
*/
public void recordConnectionUsage(long usageMilleseconds);
/**
* This method is called when a Connection is closed, with the total time in milliseconds
* that the Connection was out of the pool.
*
* @param usageMilleseconds the Connection usage time in milliseconds
*/
public void recordConnectionUsage(long usageMilleseconds);
/**
* A base instance of a MetricsContext. Classes extending this class should exhibit the
* behavior of "starting" a timer upon contruction, and "stopping" the timer when the
* {@#stop()} method is called.
*
* @author Brett Wooldridge
*/
public static class MetricsContext
{
public void stop()
{
// do nothing
}
}
/**
* A base instance of a MetricsContext. Classes extending this class should exhibit the
* behavior of "starting" a timer upon contruction, and "stopping" the timer when the
* {@#stop()} method is called.
*
* @author Brett Wooldridge
*/
public static class MetricsContext
{
public void stop()
{
// do nothing
}
}
}

@ -24,13 +24,13 @@ import com.zaxxer.hikari.util.PoolUtilities;
*/
public final class MetricsFactory
{
private MetricsFactory()
{
// private contructor
}
private MetricsFactory()
{
// private contructor
}
public static final IMetricsTracker createMetricsTracker(String metricsClassName, String poolName)
{
return PoolUtilities.createInstance(metricsClassName, IMetricsTracker.class, poolName);
}
public static final IMetricsTracker createMetricsTracker(String metricsClassName, String poolName)
{
return PoolUtilities.createInstance(metricsClassName, IMetricsTracker.class, poolName);
}
}

@ -16,7 +16,6 @@
package com.zaxxer.hikari.metrics;
/**
* This class does absolutely nothing.
*
@ -24,22 +23,22 @@ package com.zaxxer.hikari.metrics;
*/
public class MetricsTracker implements IMetricsTracker
{
public static final MetricsContext NO_CONTEXT = new MetricsContext();
public static final MetricsContext NO_CONTEXT = new MetricsContext();
public MetricsTracker()
{
}
public MetricsTracker()
{
}
public MetricsTracker(String poolName)
{
}
public MetricsTracker(String poolName)
{
}
public MetricsContext recordConnectionRequest(long requestTime)
{
return NO_CONTEXT;
}
public MetricsContext recordConnectionRequest(long requestTime)
{
return NO_CONTEXT;
}
public void recordConnectionUsage(long usageMilleseconds)
{
}
public void recordConnectionUsage(long usageMilleseconds)
{
}
}

@ -33,70 +33,62 @@ import com.zaxxer.hikari.HikariConfig;
*/
public final class HikariMBeanElf
{
private static final Logger LOGGER = LoggerFactory.getLogger(HikariMBeanElf.class);
private static final Logger LOGGER = LoggerFactory.getLogger(HikariMBeanElf.class);
private HikariMBeanElf()
{
// utility class
}
private HikariMBeanElf()
{
// utility class
}
/**
* Register MBeans for HikariConfig and HikariPool.
*
* @param configuration a HikariConfig instance
* @param pool a HikariPool instance
*/
public static void registerMBeans(HikariConfig configuration, HikariPool pool)
{
try
{
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
/**
* Register MBeans for HikariConfig and HikariPool.
*
* @param configuration a HikariConfig instance
* @param pool a HikariPool instance
*/
public static void registerMBeans(HikariConfig configuration, HikariPool pool)
{
try {
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ObjectName poolConfigName = new ObjectName("com.zaxxer.hikari:type=PoolConfig (" + configuration.getPoolName() + ")");
ObjectName poolName = new ObjectName("com.zaxxer.hikari:type=Pool (" + configuration.getPoolName() + ")");
if (!mBeanServer.isRegistered(poolConfigName))
{
mBeanServer.registerMBean(configuration, poolConfigName);
mBeanServer.registerMBean(pool, poolName);
}
else
{
LOGGER.error("You cannot use the same HikariConfig for separate pool instances.");
}
}
catch (Exception e)
{
LOGGER.warn("Unable to register management beans.", e);
}
}
ObjectName poolConfigName = new ObjectName("com.zaxxer.hikari:type=PoolConfig (" + configuration.getPoolName() + ")");
ObjectName poolName = new ObjectName("com.zaxxer.hikari:type=Pool (" + configuration.getPoolName() + ")");
if (!mBeanServer.isRegistered(poolConfigName)) {
mBeanServer.registerMBean(configuration, poolConfigName);
mBeanServer.registerMBean(pool, poolName);
}
else {
LOGGER.error("You cannot use the same HikariConfig for separate pool instances.");
}
}
catch (Exception e) {
LOGGER.warn("Unable to register management beans.", e);
}
}
/**
* Unregister MBeans for HikariConfig and HikariPool.
*
* @param configuration a HikariConfig instance
* @param pool a HikariPool instance
*/
public static void unregisterMBeans(HikariConfig configuration, HikariPool pool)
{
try
{
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
/**
* Unregister MBeans for HikariConfig and HikariPool.
*
* @param configuration a HikariConfig instance
* @param pool a HikariPool instance
*/
public static void unregisterMBeans(HikariConfig configuration, HikariPool pool)
{
try {
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ObjectName poolConfigName = new ObjectName("com.zaxxer.hikari:type=PoolConfig (" + configuration.getPoolName() + ")");
ObjectName poolName = new ObjectName("com.zaxxer.hikari:type=Pool (" + configuration.getPoolName() + ")");
if (mBeanServer.isRegistered(poolConfigName))
{
mBeanServer.unregisterMBean(poolConfigName);
mBeanServer.unregisterMBean(poolName);
}
else
{
LOGGER.error("No registered MBean for {}.", configuration.getPoolName());
}
}
catch (Exception e)
{
LOGGER.warn("Unable to unregister management beans.", e);
}
}
ObjectName poolConfigName = new ObjectName("com.zaxxer.hikari:type=PoolConfig (" + configuration.getPoolName() + ")");
ObjectName poolName = new ObjectName("com.zaxxer.hikari:type=Pool (" + configuration.getPoolName() + ")");
if (mBeanServer.isRegistered(poolConfigName)) {
mBeanServer.unregisterMBean(poolConfigName);
mBeanServer.unregisterMBean(poolName);
}
else {
LOGGER.error("No registered MBean for {}.", configuration.getPoolName());
}
}
catch (Exception e) {
LOGGER.warn("Unable to unregister management beans.", e);
}
}
}

File diff suppressed because it is too large Load Diff

@ -23,13 +23,13 @@ package com.zaxxer.hikari.pool;
*/
public interface HikariPoolMBean
{
int getIdleConnections();
int getIdleConnections();
int getActiveConnections();
int getActiveConnections();
int getTotalConnections();
int getTotalConnections();
int getThreadsAwaitingConnection();
int getThreadsAwaitingConnection();
void closeIdleConnections();
void closeIdleConnections();
}

@ -25,13 +25,13 @@ import java.sql.CallableStatement;
*/
public abstract class CallableStatementProxy extends PreparedStatementProxy implements CallableStatement
{
protected CallableStatementProxy(ConnectionProxy connection, CallableStatement statement)
{
super(connection, statement);
}
protected CallableStatementProxy(ConnectionProxy connection, CallableStatement statement)
{
super(connection, statement);
}
// **********************************************************************
// Overridden java.sql.CallableStatement Methods
// **********************************************************************
// **********************************************************************
// Overridden java.sql.CallableStatement Methods
// **********************************************************************
}

File diff suppressed because it is too large Load Diff

@ -31,76 +31,76 @@ import com.zaxxer.hikari.util.ConcurrentBag.IBagManagable;
*/
public interface IHikariConnectionProxy extends Connection, IBagManagable
{
/**
* Catpure the stack and start leak detection.
*
* @param leakThreshold the number of milliseconds before a leak is reported
* @param houseKeepingTimer the timer to run the leak detection task with
*/
void captureStack(long leakThreshold, Timer houseKeepingTimer);
/**
* Catpure the stack and start leak detection.
*
* @param leakThreshold the number of milliseconds before a leak is reported
* @param houseKeepingTimer the timer to run the leak detection task with
*/
void captureStack(long leakThreshold, Timer houseKeepingTimer);
/**
* Check if the provided SQLException contains a SQLSTATE that indicates
* a disconnection from the server.
*
* @param sqle the SQLException to check
*/
void checkException(SQLException sqle);
/**
* Check if the provided SQLException contains a SQLSTATE that indicates
* a disconnection from the server.
*
* @param sqle the SQLException to check
*/
void checkException(SQLException sqle);
/**
* Get the expiration timestamp of the connection.
*
* @return the expiration timestamp, or Long.MAX_VALUE if there is no maximum lifetime
*/
long getExpirationTime();
/**
* Get the expiration timestamp of the connection.
*
* @return the expiration timestamp, or Long.MAX_VALUE if there is no maximum lifetime
*/
long getExpirationTime();
/**
* Get the last access timestamp of the connection.
*
* @return the last access timestamp
*/
long getLastAccess();
/**
* Get the last access timestamp of the connection.
*
* @return the last access timestamp
*/
long getLastAccess();
/**
* Get the timestamp of when the connection was removed from the pool for use.
*
* @return the timestamp the connection started to be used in the most recent request
*/
long getLastOpenTime();
/**
* Get the timestamp of when the connection was removed from the pool for use.
*
* @return the timestamp the connection started to be used in the most recent request
*/
long getLastOpenTime();
/**
* Return the broken state of the connection. If checkException() detected
* a broken connection, this method will return true, otherwise false.
*
* @return the broken state of the connection
*/
boolean isBrokenConnection();
/**
* Return the broken state of the connection. If checkException() detected
* a broken connection, this method will return true, otherwise false.
*
* @return the broken state of the connection
*/
boolean isBrokenConnection();
/**
* Actually close the underlying delegate Connection.
*
* @throws SQLException rethrown from the underlying delegate Connection
*/
void realClose() throws SQLException;
/**
* Actually close the underlying delegate Connection.
*
* @throws SQLException rethrown from the underlying delegate Connection
*/
void realClose() throws SQLException;
/**
* Reset the delegate Connection back to pristine state.
*
* @throws SQLException thrown if there is an error resetting any of the state
*/
void resetConnectionState() throws SQLException;
/**
* Reset the delegate Connection back to pristine state.
*
* @throws SQLException thrown if there is an error resetting any of the state
*/
void resetConnectionState() throws SQLException;
/**
* Make the Connection available for use again by marking it as not closed.
* @param now the current time in milliseconds
*/
void unclose(long now);
/**
* Make the Connection available for use again by marking it as not closed.
* @param now the current time in milliseconds
*/
void unclose(long now);
/**
* Called by Statement and its subclasses when they are closed to remove them
* from the tracking list.
*
* @param statement the Statement to remove from tracking
*/
void untrackStatement(Statement statement);
/**
* Called by Statement and its subclasses when they are closed to remove them
* from the tracking list.
*
* @param statement the Statement to remove from tracking
*/
void untrackStatement(Statement statement);
}

@ -45,191 +45,166 @@ import com.zaxxer.hikari.util.ClassLoaderUtils;
*/
public final class JavassistProxyFactory
{
private ClassPool classPool;
static
{
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
try
{
Thread.currentThread().setContextClassLoader(JavassistProxyFactory.class.getClassLoader());
JavassistProxyFactory proxyFactoryFactory = new JavassistProxyFactory();
proxyFactoryFactory.modifyProxyFactory();
}
catch (Exception e)
{
LoggerFactory.getLogger(JavassistProxyFactory.class).error("Fatal exception during proxy generation", e);
throw new RuntimeException(e);
}
finally
{
Thread.currentThread().setContextClassLoader(contextClassLoader);
}
}
/**
* Simply invoking this method causes the initialization of this class. All work
* by this class is performed in static initialization.
*/
public static void initialize()
{
// no-op
}
private JavassistProxyFactory()
{
classPool = new ClassPool();
classPool.importPackage("java.sql");
classPool.appendClassPath(new LoaderClassPath(this.getClass().getClassLoader()));
try
{
// Connection is special, it has a checkClosed() call at the beginning
String methodBody = "{ checkClosed(); try { return delegate.method($$); } catch (SQLException e) { checkException(e); throw e;} }";
generateProxyClass(Connection.class, ConnectionProxy.class, methodBody);
// Cast is not needed for these
methodBody = "{ try { return delegate.method($$); } catch (SQLException e) { checkException(e); throw e;} }";
generateProxyClass(Statement.class, StatementProxy.class, methodBody);
// For these we have to cast the delegate
methodBody = "{ try { return ((cast) delegate).method($$); } catch (SQLException e) { checkException(e); throw e;} }";
generateProxyClass(PreparedStatement.class, PreparedStatementProxy.class, methodBody);
generateProxyClass(CallableStatement.class, CallableStatementProxy.class, methodBody);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
private void modifyProxyFactory() throws Exception
{
String packageName = JavassistProxyFactory.class.getPackage().getName();
CtClass proxyCt = classPool.getCtClass("com.zaxxer.hikari.proxy.ProxyFactory");
for (CtMethod method : proxyCt.getMethods())
{
String methodName = method.getName();
if ("getProxyConnection".equals(methodName))
{
method.setBody("{return new " + packageName + ".ConnectionJavassistProxy($$);}");
private ClassPool classPool;
static {
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(JavassistProxyFactory.class.getClassLoader());
JavassistProxyFactory proxyFactoryFactory = new JavassistProxyFactory();
proxyFactoryFactory.modifyProxyFactory();
}
catch (Exception e) {
LoggerFactory.getLogger(JavassistProxyFactory.class).error("Fatal exception during proxy generation", e);
throw new RuntimeException(e);
}
finally {
Thread.currentThread().setContextClassLoader(contextClassLoader);
}
}
/**
* Simply invoking this method causes the initialization of this class. All work
* by this class is performed in static initialization.
*/
public static void initialize()
{
// no-op
}
private JavassistProxyFactory()
{
classPool = new ClassPool();
classPool.importPackage("java.sql");
classPool.appendClassPath(new LoaderClassPath(this.getClass().getClassLoader()));
try {
// Connection is special, it has a checkClosed() call at the beginning
String methodBody = "{ checkClosed(); try { return delegate.method($$); } catch (SQLException e) { checkException(e); throw e;} }";
generateProxyClass(Connection.class, ConnectionProxy.class, methodBody);
// Cast is not needed for these
methodBody = "{ try { return delegate.method($$); } catch (SQLException e) { checkException(e); throw e;} }";
generateProxyClass(Statement.class, StatementProxy.class, methodBody);
// For these we have to cast the delegate
methodBody = "{ try { return ((cast) delegate).method($$); } catch (SQLException e) { checkException(e); throw e;} }";
generateProxyClass(PreparedStatement.class, PreparedStatementProxy.class, methodBody);
generateProxyClass(CallableStatement.class, CallableStatementProxy.class, methodBody);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
private void modifyProxyFactory() throws Exception
{
String packageName = JavassistProxyFactory.class.getPackage().getName();
CtClass proxyCt = classPool.getCtClass("com.zaxxer.hikari.proxy.ProxyFactory");
for (CtMethod method : proxyCt.getMethods()) {
String methodName = method.getName();
if ("getProxyConnection".equals(methodName)) {
method.setBody("{return new " + packageName + ".ConnectionJavassistProxy($$);}");
}
else if ("getProxyStatement".equals(methodName)) {
method.setBody("{return new " + packageName + ".StatementJavassistProxy($$);}");
}
else if ("getProxyPreparedStatement".equals(methodName)) {
method.setBody("{return new " + packageName + ".PreparedStatementJavassistProxy($$);}");
}
else if ("getProxyCallableStatement".equals(methodName)) {
method.setBody("{return new " + packageName + ".CallableStatementJavassistProxy($$);}");
}
}
proxyCt.toClass(classPool.getClassLoader(), null);
}
/**
* Generate Javassist Proxy Classes
*/
@SuppressWarnings("unchecked")
private <T> Class<T> generateProxyClass(Class<T> primaryInterface, Class<?> superClass, String methodBody) throws Exception
{
// Make a new class that extends one of the JavaProxy classes (ie. superClass); use the name to XxxJavassistProxy instead of XxxProxy
String superClassName = superClass.getName();
CtClass superClassCt = classPool.getCtClass(superClassName);
CtClass targetCt = classPool.makeClass(superClassName.replace("Proxy", "JavassistProxy"), superClassCt);
targetCt.setModifiers(Modifier.FINAL);
// Make a set of method signatures we inherit implementation for, so we don't generate delegates for these
Set<String> superSigs = new HashSet<String>();
for (CtMethod method : superClassCt.getMethods()) {
if ((method.getModifiers() & Modifier.ABSTRACT) != Modifier.ABSTRACT) {
superSigs.add(method.getName() + method.getSignature());
}
}
methodBody = methodBody.replace("cast", primaryInterface.getName());
Set<String> methods = new HashSet<String>();
Set<Class<?>> interfaces = ClassLoaderUtils.getAllInterfaces(primaryInterface);
for (Class<?> intf : interfaces) {
CtClass intfCt = classPool.getCtClass(intf.getName());
targetCt.addInterface(intfCt);
for (CtMethod intfMethod : intfCt.getDeclaredMethods()) {
final String signature = intfMethod.getName() + intfMethod.getSignature();
// don't generate delegates for methods we override
if (superSigs.contains(signature)) {
continue;
}
else if ("getProxyStatement".equals(methodName))
{
method.setBody("{return new " + packageName + ".StatementJavassistProxy($$);}");
}
else if ("getProxyPreparedStatement".equals(methodName))
{
method.setBody("{return new " + packageName + ".PreparedStatementJavassistProxy($$);}");
// Ignore already added methods that come from other interfaces
if (methods.contains(signature)) {
continue;
}
else if ("getProxyCallableStatement".equals(methodName))
{
method.setBody("{return new " + packageName + ".CallableStatementJavassistProxy($$);}");
// Track what methods we've added
methods.add(signature);
// Clone the method we want to inject into
CtMethod method = CtNewMethod.copy(intfMethod, targetCt, null);
// Generate a method that simply invokes the same method on the delegate
String modifiedBody;
if (isThrowsSqlException(intfMethod)) {
modifiedBody = methodBody.replace("method", method.getName());
}
}
proxyCt.toClass(classPool.getClassLoader(), null);
}
/**
* Generate Javassist Proxy Classes
*/
@SuppressWarnings("unchecked")
private <T> Class<T> generateProxyClass(Class<T> primaryInterface, Class<?> superClass, String methodBody) throws Exception
{
// Make a new class that extends one of the JavaProxy classes (ie. superClass); use the name to XxxJavassistProxy instead of XxxProxy
String superClassName = superClass.getName();
CtClass superClassCt = classPool.getCtClass(superClassName);
CtClass targetCt = classPool.makeClass(superClassName.replace("Proxy", "JavassistProxy"), superClassCt);
targetCt.setModifiers(Modifier.FINAL);
// Make a set of method signatures we inherit implementation for, so we don't generate delegates for these
Set<String> superSigs = new HashSet<String>();
for (CtMethod method : superClassCt.getMethods())
{
if ((method.getModifiers() & Modifier.ABSTRACT) != Modifier.ABSTRACT)
{
superSigs.add(method.getName() + method.getSignature());
else {
modifiedBody = "{ return ((cast) delegate).method($$); }".replace("method", method.getName()).replace("cast", primaryInterface.getName());
}
}
methodBody = methodBody.replace("cast", primaryInterface.getName());
Set<String> methods = new HashSet<String>();
Set<Class<?>> interfaces = ClassLoaderUtils.getAllInterfaces(primaryInterface);
for (Class<?> intf : interfaces)
{
CtClass intfCt = classPool.getCtClass(intf.getName());
targetCt.addInterface(intfCt);
for (CtMethod intfMethod : intfCt.getDeclaredMethods())
{
final String signature = intfMethod.getName() + intfMethod.getSignature();
// don't generate delegates for methods we override
if (superSigs.contains(signature))
{
continue;
}
// Ignore already added methods that come from other interfaces
if (methods.contains(signature))
{
continue;
}
// Track what methods we've added
methods.add(signature);
// Clone the method we want to inject into
CtMethod method = CtNewMethod.copy(intfMethod, targetCt, null);
// Generate a method that simply invokes the same method on the delegate
String modifiedBody;
if (isThrowsSqlException(intfMethod))
{
modifiedBody = methodBody.replace("method", method.getName());
}
else
{
modifiedBody = "{ return ((cast) delegate).method($$); }".replace("method", method.getName()).replace("cast", primaryInterface.getName());
}
if (method.getReturnType() == CtClass.voidType)
{
modifiedBody = modifiedBody.replace("return", "");
}
method.setBody(modifiedBody);
targetCt.addMethod(method);
if (method.getReturnType() == CtClass.voidType) {
modifiedBody = modifiedBody.replace("return", "");
}
}
if (LoggerFactory.getLogger(getClass()).isDebugEnabled())
{
targetCt.debugWriteFile(System.getProperty("java.io.tmpdir"));
}
return targetCt.toClass(classPool.getClassLoader(), null);
}
private boolean isThrowsSqlException(CtMethod method)
{
try
{
for (CtClass clazz : method.getExceptionTypes())
{
if (clazz.getSimpleName().equals("SQLException"))
{
return true;
}
method.setBody(modifiedBody);
targetCt.addMethod(method);
}
}
if (LoggerFactory.getLogger(getClass()).isDebugEnabled()) {
targetCt.debugWriteFile(System.getProperty("java.io.tmpdir"));
}
return targetCt.toClass(classPool.getClassLoader(), null);
}
private boolean isThrowsSqlException(CtMethod method)
{
try {
for (CtClass clazz : method.getExceptionTypes()) {
if (clazz.getSimpleName().equals("SQLException")) {
return true;
}
}
catch (NotFoundException e)
{
// fall thru
}
return false;
}
}
}
catch (NotFoundException e) {
// fall thru
}
return false;
}
}

@ -25,36 +25,34 @@ import org.slf4j.LoggerFactory;
*/
class LeakTask extends TimerTask
{
private final long leakTime;
private StackTraceElement[] stackTrace;
private final long leakTime;
private StackTraceElement[] stackTrace;
public LeakTask(StackTraceElement[] stackTrace, long leakDetectionThreshold)
{
this.stackTrace = stackTrace;
this.leakTime = System.currentTimeMillis() + leakDetectionThreshold;
}
public LeakTask(StackTraceElement[] stackTrace, long leakDetectionThreshold)
{
this.stackTrace = stackTrace;
this.leakTime = System.currentTimeMillis() + leakDetectionThreshold;
}
/** {@inheritDoc} */
@Override
public void run()
{
if (System.currentTimeMillis() > leakTime)
{
Exception e = new Exception();
e.setStackTrace(stackTrace);
LoggerFactory.getLogger(LeakTask.class).warn("Connection leak detection triggered, stack trace follows", e);
stackTrace = null;
}
}
/** {@inheritDoc} */
@Override
public void run()
{
if (System.currentTimeMillis() > leakTime) {
Exception e = new Exception();
e.setStackTrace(stackTrace);
LoggerFactory.getLogger(LeakTask.class).warn("Connection leak detection triggered, stack trace follows", e);
stackTrace = null;
}
}
@Override
public boolean cancel()
{
boolean cancelled = super.cancel();
if (cancelled)
{
stackTrace = null;
}
return cancelled;
}
@Override
public boolean cancel()
{
boolean cancelled = super.cancel();
if (cancelled) {
stackTrace = null;
}
return cancelled;
}
}

@ -27,27 +27,25 @@ import java.sql.SQLException;
*/
public abstract class PreparedStatementProxy extends StatementProxy implements PreparedStatement
{
protected PreparedStatementProxy(ConnectionProxy connection, PreparedStatement statement)
{
super(connection, statement);
}
protected PreparedStatementProxy(ConnectionProxy connection, PreparedStatement statement)
{
super(connection, statement);
}
// **********************************************************************
// Overridden java.sql.PreparedStatement Methods
// **********************************************************************
// **********************************************************************
// Overridden java.sql.PreparedStatement Methods
// **********************************************************************
/** {@inheritDoc} */
@Override
public final ResultSet executeQuery() throws SQLException
{
try
{
return ((PreparedStatement) delegate).executeQuery();
}
catch (SQLException e)
{
connection.checkException(e);
throw e;
}
}
/** {@inheritDoc} */
@Override
public final ResultSet executeQuery() throws SQLException
{
try {
return ((PreparedStatement) delegate).executeQuery();
}
catch (SQLException e) {
connection.checkException(e);
throw e;
}
}
}

@ -31,44 +31,45 @@ import com.zaxxer.hikari.pool.HikariPool;
*/
public final class ProxyFactory
{
private ProxyFactory()
{
// unconstructable
}
private ProxyFactory()
{
// unconstructable
}
/**
* Create a proxy for the specified {@link Connection} instance.
*
* @param pool the {@link HikariPool} that will own this proxy
* @param connection the {@link Connection} that will be wrapped by this proxy
* @param maxLifeTime the lifetime of the connection
* @param defaultIsolationLevel the default transaction isolation level of the underlying {@link Connection}
* @param defaultAutoCommit the default auto-commit state of the underlying {@link Connection}
* @param defaultIReadOnly the default readOnly state of the underlying {@link Connection}
* @param defaultCatalog the default catalog of the underlying {@link Connection}
* @return a proxy that wraps the specified {@link Connection}
*/
public static IHikariConnectionProxy getProxyConnection(HikariPool pool, Connection connection, long maxLifeTime, int defaultIsolationLevel, boolean defaultAutoCommit, boolean defaultIReadOnly, String defaultCatalog)
{
// Body is injected by JavassistProxyFactory
return null;
}
/**
* Create a proxy for the specified {@link Connection} instance.
*
* @param pool the {@link HikariPool} that will own this proxy
* @param connection the {@link Connection} that will be wrapped by this proxy
* @param maxLifeTime the lifetime of the connection
* @param defaultIsolationLevel the default transaction isolation level of the underlying {@link Connection}
* @param defaultAutoCommit the default auto-commit state of the underlying {@link Connection}
* @param defaultIReadOnly the default readOnly state of the underlying {@link Connection}
* @param defaultCatalog the default catalog of the underlying {@link Connection}
* @return a proxy that wraps the specified {@link Connection}
*/
public static IHikariConnectionProxy getProxyConnection(HikariPool pool, Connection connection, long maxLifeTime, int defaultIsolationLevel,
boolean defaultAutoCommit, boolean defaultIReadOnly, String defaultCatalog)
{
// Body is injected by JavassistProxyFactory
return null;
}
static Statement getProxyStatement(ConnectionProxy connection, Statement statement)
{
// Body is injected by JavassistProxyFactory
return null;
}
static Statement getProxyStatement(ConnectionProxy connection, Statement statement)
{
// Body is injected by JavassistProxyFactory
return null;
}
static CallableStatement getProxyCallableStatement(ConnectionProxy connection, CallableStatement statement)
{
// Body is injected by JavassistProxyFactory
return null;
}
static CallableStatement getProxyCallableStatement(ConnectionProxy connection, CallableStatement statement)
{
// Body is injected by JavassistProxyFactory
return null;
}
static PreparedStatement getProxyPreparedStatement(ConnectionProxy connection, PreparedStatement statement)
{
// Body is injected by JavassistProxyFactory
return null;
}
static PreparedStatement getProxyPreparedStatement(ConnectionProxy connection, PreparedStatement statement)
{
// Body is injected by JavassistProxyFactory
return null;
}
}

@ -28,110 +28,100 @@ import java.sql.Statement;
*/
public abstract class StatementProxy implements Statement
{
protected final IHikariConnectionProxy connection;
protected final Statement delegate;
private boolean isClosed;
protected StatementProxy(IHikariConnectionProxy connection, Statement statement)
{
this.connection = connection;
this.delegate = statement;
}
protected final void checkException(SQLException e)
{
connection.checkException(e);
}
// **********************************************************************
// Overridden java.sql.Statement Methods
// **********************************************************************
/** {@inheritDoc} */
@Override
public final void close() throws SQLException
{
if (isClosed)
{
return;
}
isClosed = true;
connection.untrackStatement(this);
try
{
delegate.close();
}
catch (SQLException e)
{
connection.checkException(e);
throw e;
}
}
/** {@inheritDoc} */
@Override
public final ResultSet executeQuery(String sql) throws SQLException
{
try
{
return delegate.executeQuery(sql);
}
catch (SQLException e)
{
connection.checkException(e);
throw e;
}
}
/** {@inheritDoc} */
@Override
public final ResultSet getResultSet() throws SQLException
{
try
{
return delegate.getResultSet();
}
catch (SQLException e)
{
connection.checkException(e);
throw e;
}
}
/** {@inheritDoc} */
@Override
public final ResultSet getGeneratedKeys() throws SQLException
{
try
{
return delegate.getGeneratedKeys();
}
catch (SQLException e)
{
connection.checkException(e);
throw e;
}
}
/** {@inheritDoc} */
@Override
public final Connection getConnection() throws SQLException
{
return connection;
}
@Override
@SuppressWarnings("unchecked")
public final <T> T unwrap(Class<T> iface) throws SQLException
{
if (iface.isInstance(delegate))
{
return (T) delegate;
}
throw new SQLException("Wrapped connection is not an instance of " + iface);
}
protected final IHikariConnectionProxy connection;
protected final Statement delegate;
private boolean isClosed;
protected StatementProxy(IHikariConnectionProxy connection, Statement statement)
{
this.connection = connection;
this.delegate = statement;
}
protected final void checkException(SQLException e)
{
connection.checkException(e);
}
// **********************************************************************
// Overridden java.sql.Statement Methods
// **********************************************************************
/** {@inheritDoc} */
@Override
public final void close() throws SQLException
{
if (isClosed) {
return;
}
isClosed = true;
connection.untrackStatement(this);
try {
delegate.close();
}
catch (SQLException e) {
connection.checkException(e);
throw e;
}
}
/** {@inheritDoc} */
@Override
public final ResultSet executeQuery(String sql) throws SQLException
{
try {
return delegate.executeQuery(sql);
}
catch (SQLException e) {
connection.checkException(e);
throw e;
}
}
/** {@inheritDoc} */
@Override
public final ResultSet getResultSet() throws SQLException
{
try {
return delegate.getResultSet();
}
catch (SQLException e) {
connection.checkException(e);
throw e;
}
}
/** {@inheritDoc} */
@Override
public final ResultSet getGeneratedKeys() throws SQLException
{
try {
return delegate.getGeneratedKeys();
}
catch (SQLException e) {
connection.checkException(e);
throw e;
}
}
/** {@inheritDoc} */
@Override
public final Connection getConnection() throws SQLException
{
return connection;
}
@Override
@SuppressWarnings("unchecked")
public final <T> T unwrap(Class<T> iface) throws SQLException
{
if (iface.isInstance(delegate)) {
return (T) delegate;
}
throw new SQLException("Wrapped connection is not an instance of " + iface);
}
}

@ -26,76 +26,68 @@ import java.util.Set;
*/
public final class ClassLoaderUtils
{
/**
* Get the class loader which can be used to generate proxies without leaking memory.
* @return the class loader which can be used to generate proxies without leaking memory.
*/
public static ClassLoader getClassLoader()
{
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl != null)
{
return new CascadingClassLoader(cl);
}
return ClassLoaderUtils.class.getClassLoader();
}
/**
* Get the class loader which can be used to generate proxies without leaking memory.
* @return the class loader which can be used to generate proxies without leaking memory.
*/
public static ClassLoader getClassLoader()
{
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl != null) {
return new CascadingClassLoader(cl);
}
return ClassLoaderUtils.class.getClassLoader();
}
public static Class<?> loadClass(String className) throws ClassNotFoundException
{
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl != null)
{
return new CascadingClassLoader(cl).loadClass(className);
}
public static Class<?> loadClass(String className) throws ClassNotFoundException
{
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl != null) {
return new CascadingClassLoader(cl).loadClass(className);
}
return Class.forName(className);
}
return Class.forName(className);
}
public static Set<Class<?>> getAllInterfaces(Class<?> clazz)
{
Set<Class<?>> interfaces = new HashSet<Class<?>>();
for (Class<?> intf : Arrays.asList(clazz.getInterfaces()))
{
if (intf.getInterfaces().length > 0)
{
interfaces.addAll(getAllInterfaces(intf));
}
interfaces.add(intf);
}
if (clazz.getSuperclass() != null)
{
interfaces.addAll(getAllInterfaces(clazz.getSuperclass()));
}
public static Set<Class<?>> getAllInterfaces(Class<?> clazz)
{
Set<Class<?>> interfaces = new HashSet<Class<?>>();
for (Class<?> intf : Arrays.asList(clazz.getInterfaces())) {
if (intf.getInterfaces().length > 0) {
interfaces.addAll(getAllInterfaces(intf));
}
interfaces.add(intf);
}
if (clazz.getSuperclass() != null) {
interfaces.addAll(getAllInterfaces(clazz.getSuperclass()));
}
if (clazz.isInterface())
{
interfaces.add(clazz);
}
if (clazz.isInterface()) {
interfaces.add(clazz);
}
return interfaces;
}
return interfaces;
}
private static class CascadingClassLoader extends ClassLoader
{
private ClassLoader contextLoader;
private static class CascadingClassLoader extends ClassLoader
{
private ClassLoader contextLoader;
CascadingClassLoader(ClassLoader contextLoader)
{
this.contextLoader = contextLoader;
}
CascadingClassLoader(ClassLoader contextLoader)
{
this.contextLoader = contextLoader;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException
{
try
{
return contextLoader.loadClass(name);
}
catch (ClassNotFoundException cnfe)
{
return CascadingClassLoader.class.getClassLoader().loadClass(name);
}
}
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException
{
try {
return contextLoader.loadClass(name);
}
catch (ClassNotFoundException cnfe) {
return CascadingClassLoader.class.getClassLoader().loadClass(name);
}
}
}
}

@ -44,323 +44,300 @@ import java.util.concurrent.locks.AbstractQueuedLongSynchronizer;
*/
public class ConcurrentBag<T extends com.zaxxer.hikari.util.ConcurrentBag.IBagManagable>
{
public static final int STATE_NOT_IN_USE = 0;
public static final int STATE_IN_USE = 1;
private static final int STATE_REMOVED = -1;
private static final int STATE_RESERVED = -2;
/**
* This interface must be implemented by classes wishing to be managed by
* ConcurrentBag. All implementations must be atomic with respect to state.
* The suggested implementation is via AtomicInteger using the methods
* <code>get()</code> and <code>compareAndSet()</code>.
*/
public interface IBagManagable
{
int getState();
boolean compareAndSetState(int expectedState, int newState);
}
/**
* This interface is implemented by a listener to the bag. The listener
* will be informed of when the bag has become empty. The usual course
* of action by the listener in this case is to attempt to add an item
* to the bag.
*/
public interface IBagStateListener
{
void addBagItem();
}
private ThreadLocal<FastList<WeakReference<T>>> threadList;
private CopyOnWriteArraySet<T> sharedList;
private Synchronizer synchronizer;
private IBagStateListener listener;
/**
* Constructor.
*/
public ConcurrentBag()
{
this.sharedList = new CopyOnWriteArraySet<T>();
this.synchronizer = new Synchronizer();
this.threadList = new ThreadLocal<FastList<WeakReference<T>>>();
}
/**
* The method will borrow an IBagManagable from the bag, blocking for the
* specified timeout if none are available.
*
* @param timeout how long to wait before giving up, in units of unit
* @param timeUnit a <code>TimeUnit</code> determining how to interpret the timeout parameter
* @return a borrowed instance from the bag or null if a timeout occurs
* @throws InterruptedException if interrupted while waiting
*/
public T borrow(long timeout, TimeUnit timeUnit) throws InterruptedException
{
// Try the thread-local list first
FastList<WeakReference<T>> list = threadList.get();
if (list == null)
{
list = new FastList<WeakReference<T>>(WeakReference.class);
threadList.set(list);
}
else
{
for (int i = list.size() - 1; i >= 0; i--)
{
final WeakReference<T> reference = list.removeLast();
final T element = reference.get();
if (element != null && element.compareAndSetState(STATE_NOT_IN_USE, STATE_IN_USE))
{
return element;
}
}
}
// Otherwise, scan the shared list ... for maximum of timeout
timeout = timeUnit.toNanos(timeout);
do {
final long startScan = System.nanoTime();
for (T reference : sharedList)
{
if (reference.compareAndSetState(STATE_NOT_IN_USE, STATE_IN_USE))
{
return reference;
}
}
if (listener != null)
{
listener.addBagItem();
}
synchronizer.tryAcquireSharedNanos(startScan, timeout);
timeout -= (System.nanoTime() - startScan);
} while (timeout > 0);
return null;
}
/**
* This method will return a borrowed object to the bag. Objects
* that are borrowed from the bag but never "requited" will result
* in a memory leak.
*
* @param value the value to return to the bag
* @throws NullPointerException if value is null
* @throws IllegalStateException if the requited value was not borrowed from the bag
*/
public void requite(final T value)
{
if (value == null)
{
throw new NullPointerException("Cannot return a null value to the bag");
}
if (value.compareAndSetState(STATE_IN_USE, STATE_NOT_IN_USE))
{
FastList<WeakReference<T>> list = threadList.get();
if (list == null)
{
list = new FastList<WeakReference<T>>(WeakReference.class);
threadList.set(list);
}
list.add(new WeakReference<T>(value));
synchronizer.releaseShared(System.nanoTime());
}
else
{
throw new IllegalStateException("Value was returned to the bag that was not borrowed: ");
}
}
/**
* Add a new object to the bag for others to borrow.
*
* @param value an object to add to the bag
*/
public void add(final T value)
{
final long addTime = System.nanoTime();
sharedList.add(value);
synchronizer.releaseShared(addTime);
}
/**
* Remove a value from the bag. This method should only be called
* with objects obtained by {@link #borrow(long, TimeUnit)} or {@link #reserve(IBagManagable)}.
* @param value the value to remove
* @throws IllegalStateException if an attempt is made to remove an object
* from the bag that was not borrowed or reserved first
*/
public void remove(T value)
{
if (value.compareAndSetState(STATE_IN_USE, STATE_REMOVED) || value.compareAndSetState(STATE_RESERVED, STATE_REMOVED))
{
if (!sharedList.remove(value))
{
throw new IllegalStateException("Attempt to remove an object from the bag that does not exist");
}
}
else
{
throw new IllegalStateException("Attempt to remove an object from the bag that was not borrowed or reserved");
}
}
/**
* This method provides a "snaphot" in time of the IBagManagable
* items in the bag in the specified state. It does not "lock"
* or reserve items in any way. Call {@link #reserve(IBagManagable)}
* on items in list before performing any action on them.
*
* @param state one of STATE_NOT_IN_USE or STATE_IN_USE
* @return a possibly empty list of objects having the state specified
*/
public List<T> values(int state)
{
ArrayList<T> list = new ArrayList<T>(sharedList.size());
if (state == STATE_IN_USE || state == STATE_NOT_IN_USE)
{
for (T reference : sharedList)
{
if (reference.getState() == state)
{
list.add(reference);
}
}
}
return list;
}
/**
* The method is used to make an item in the bag "unavailable" for
* borrowing. It is primarily used when wanting to operate on items
* returned by the {@link #values(int)} method. Items that are
* reserved can be removed from the bag via {@link #remove(IBagManagable)}
* without the need to unreserve them. Items that are not removed
* from the bag can be make available for borrowing again by calling
* the {@link #unreserve(IBagManagable)} method.
*
* @param value the item to reserve
* @return true if the item was able to be reserved, false otherwise
*/
public boolean reserve(T value)
{
return value.compareAndSetState(STATE_NOT_IN_USE, STATE_RESERVED);
}
/**
* This method is used to make an item reserved via {@link #reserve(IBagManagable)}
* available again for borrowing.
*
* @param value the item to unreserve
*/
public void unreserve(T value)
{
final long checkInTime = System.nanoTime();
if (!value.compareAndSetState(STATE_RESERVED, STATE_NOT_IN_USE))
{
throw new IllegalStateException("Attempt to relinquish an object to the bag that was not reserved");
}
synchronizer.releaseShared(checkInTime);
}
/**
* Add a listener to the bag. There can only be one. If this method is
* called a second time, the original listener will be evicted.
*
* @param listener a listener to the bag
*/
public void addBagStateListener(IBagStateListener listener)
{
this.listener = listener;
}
/**
* Get the number of threads pending (waiting) for an item from the
* bag to become available.
*
* @return the number of threads waiting for items from the bag
*/
public int getPendingQueue()
{
return synchronizer.getQueueLength();
}
public int getCount(int state)
{
int count = 0;
for (T reference : sharedList)
{
if (reference.getState() == state)
{
count++;
}
}
return count;
}
/**
* Get the total number of items in the bag.
*
* @return the number of items in the bag
*/
public int size()
{
return sharedList.size();
}
/**
* Our private synchronizer that handles notify/wait type semantics.
*/
private static class Synchronizer extends AbstractQueuedLongSynchronizer
{
private static final long serialVersionUID = 104753538004341218L;
private static final boolean JAVA7;
static
{
boolean b = false;
try
{
b = AbstractQueuedLongSynchronizer.class.getMethod("hasQueuedPredecessors", new Class<?>[0]) != null;
public static final int STATE_NOT_IN_USE = 0;
public static final int STATE_IN_USE = 1;
private static final int STATE_REMOVED = -1;
private static final int STATE_RESERVED = -2;
/**
* This interface must be implemented by classes wishing to be managed by
* ConcurrentBag. All implementations must be atomic with respect to state.
* The suggested implementation is via AtomicInteger using the methods
* <code>get()</code> and <code>compareAndSet()</code>.
*/
public interface IBagManagable
{
int getState();
boolean compareAndSetState(int expectedState, int newState);
}
/**
* This interface is implemented by a listener to the bag. The listener
* will be informed of when the bag has become empty. The usual course
* of action by the listener in this case is to attempt to add an item
* to the bag.
*/
public interface IBagStateListener
{
void addBagItem();
}
private ThreadLocal<FastList<WeakReference<T>>> threadList;
private CopyOnWriteArraySet<T> sharedList;
private Synchronizer synchronizer;
private IBagStateListener listener;
/**
* Constructor.
*/
public ConcurrentBag()
{
this.sharedList = new CopyOnWriteArraySet<T>();
this.synchronizer = new Synchronizer();
this.threadList = new ThreadLocal<FastList<WeakReference<T>>>();
}
/**
* The method will borrow an IBagManagable from the bag, blocking for the
* specified timeout if none are available.
*
* @param timeout how long to wait before giving up, in units of unit
* @param timeUnit a <code>TimeUnit</code> determining how to interpret the timeout parameter
* @return a borrowed instance from the bag or null if a timeout occurs
* @throws InterruptedException if interrupted while waiting
*/
public T borrow(long timeout, TimeUnit timeUnit) throws InterruptedException
{
// Try the thread-local list first
FastList<WeakReference<T>> list = threadList.get();
if (list == null) {
list = new FastList<WeakReference<T>>(WeakReference.class);
threadList.set(list);
}
else {
for (int i = list.size() - 1; i >= 0; i--) {
final WeakReference<T> reference = list.removeLast();
final T element = reference.get();
if (element != null && element.compareAndSetState(STATE_NOT_IN_USE, STATE_IN_USE)) {
return element;
}
catch (Exception e)
{
}
}
// Otherwise, scan the shared list ... for maximum of timeout
timeout = timeUnit.toNanos(timeout);
do {
final long startScan = System.nanoTime();
for (T reference : sharedList) {
if (reference.compareAndSetState(STATE_NOT_IN_USE, STATE_IN_USE)) {
return reference;
}
JAVA7 = b;
}
@Override
protected long tryAcquireShared(long startScanTime)
{
return getState() >= startScanTime && !java67hasQueuedPredecessors() ? 1 : -1;
}
/** {@inheritDoc} */
@Override
protected boolean tryReleaseShared(long updateTime)
{
setState(updateTime);
return true;
}
private boolean java67hasQueuedPredecessors()
{
if (JAVA7)
{
return hasQueuedPredecessors();
}
if (listener != null) {
listener.addBagItem();
}
synchronizer.tryAcquireSharedNanos(startScan, timeout);
timeout -= (System.nanoTime() - startScan);
}
while (timeout > 0);
return null;
}
/**
* This method will return a borrowed object to the bag. Objects
* that are borrowed from the bag but never "requited" will result
* in a memory leak.
*
* @param value the value to return to the bag
* @throws NullPointerException if value is null
* @throws IllegalStateException if the requited value was not borrowed from the bag
*/
public void requite(final T value)
{
if (value == null) {
throw new NullPointerException("Cannot return a null value to the bag");
}
if (value.compareAndSetState(STATE_IN_USE, STATE_NOT_IN_USE)) {
FastList<WeakReference<T>> list = threadList.get();
if (list == null) {
list = new FastList<WeakReference<T>>(WeakReference.class);
threadList.set(list);
}
list.add(new WeakReference<T>(value));
synchronizer.releaseShared(System.nanoTime());
}
else {
throw new IllegalStateException("Value was returned to the bag that was not borrowed: ");
}
}
/**
* Add a new object to the bag for others to borrow.
*
* @param value an object to add to the bag
*/
public void add(final T value)
{
final long addTime = System.nanoTime();
sharedList.add(value);
synchronizer.releaseShared(addTime);
}
/**
* Remove a value from the bag. This method should only be called
* with objects obtained by {@link #borrow(long, TimeUnit)} or {@link #reserve(IBagManagable)}.
* @param value the value to remove
* @throws IllegalStateException if an attempt is made to remove an object
* from the bag that was not borrowed or reserved first
*/
public void remove(T value)
{
if (value.compareAndSetState(STATE_IN_USE, STATE_REMOVED) || value.compareAndSetState(STATE_RESERVED, STATE_REMOVED)) {
if (!sharedList.remove(value)) {
throw new IllegalStateException("Attempt to remove an object from the bag that does not exist");
}
}
else {
throw new IllegalStateException("Attempt to remove an object from the bag that was not borrowed or reserved");
}
}
/**
* This method provides a "snaphot" in time of the IBagManagable
* items in the bag in the specified state. It does not "lock"
* or reserve items in any way. Call {@link #reserve(IBagManagable)}
* on items in list before performing any action on them.
*
* @param state one of STATE_NOT_IN_USE or STATE_IN_USE
* @return a possibly empty list of objects having the state specified
*/
public List<T> values(int state)
{
ArrayList<T> list = new ArrayList<T>(sharedList.size());
if (state == STATE_IN_USE || state == STATE_NOT_IN_USE) {
for (T reference : sharedList) {
if (reference.getState() == state) {
list.add(reference);
}
return false;
}
}
}
}
return list;
}
/**
* The method is used to make an item in the bag "unavailable" for
* borrowing. It is primarily used when wanting to operate on items
* returned by the {@link #values(int)} method. Items that are
* reserved can be removed from the bag via {@link #remove(IBagManagable)}
* without the need to unreserve them. Items that are not removed
* from the bag can be make available for borrowing again by calling
* the {@link #unreserve(IBagManagable)} method.
*
* @param value the item to reserve
* @return true if the item was able to be reserved, false otherwise
*/
public boolean reserve(T value)
{
return value.compareAndSetState(STATE_NOT_IN_USE, STATE_RESERVED);
}
/**
* This method is used to make an item reserved via {@link #reserve(IBagManagable)}
* available again for borrowing.
*
* @param value the item to unreserve
*/
public void unreserve(T value)
{
final long checkInTime = System.nanoTime();
if (!value.compareAndSetState(STATE_RESERVED, STATE_NOT_IN_USE)) {
throw new IllegalStateException("Attempt to relinquish an object to the bag that was not reserved");
}
synchronizer.releaseShared(checkInTime);
}
/**
* Add a listener to the bag. There can only be one. If this method is
* called a second time, the original listener will be evicted.
*
* @param listener a listener to the bag
*/
public void addBagStateListener(IBagStateListener listener)
{
this.listener = listener;
}
/**
* Get the number of threads pending (waiting) for an item from the
* bag to become available.
*
* @return the number of threads waiting for items from the bag
*/
public int getPendingQueue()
{
return synchronizer.getQueueLength();
}
public int getCount(int state)
{
int count = 0;
for (T reference : sharedList) {
if (reference.getState() == state) {
count++;
}
}
return count;
}
/**
* Get the total number of items in the bag.
*
* @return the number of items in the bag
*/
public int size()
{
return sharedList.size();
}
/**
* Our private synchronizer that handles notify/wait type semantics.
*/
private static class Synchronizer extends AbstractQueuedLongSynchronizer
{
private static final long serialVersionUID = 104753538004341218L;
private static final boolean JAVA7;
static {
boolean b = false;
try {
b = AbstractQueuedLongSynchronizer.class.getMethod("hasQueuedPredecessors", new Class<?>[0]) != null;
}
catch (Exception e) {
}
JAVA7 = b;
}
@Override
protected long tryAcquireShared(long startScanTime)
{
return getState() >= startScanTime && !java67hasQueuedPredecessors() ? 1 : -1;
}
/** {@inheritDoc} */
@Override
protected boolean tryReleaseShared(long updateTime)
{
setState(updateTime);
return true;
}
private boolean java67hasQueuedPredecessors()
{
if (JAVA7) {
return hasQueuedPredecessors();
}
return false;
}
}
}

@ -26,91 +26,86 @@ import javax.sql.DataSource;
public final class DriverDataSource implements DataSource
{
private final String jdbcUrl;
private final Properties driverProperties;
private PrintWriter logWriter;
public DriverDataSource(String jdbcUrl, Properties properties, String username, String password)
{
try
{
this.jdbcUrl = jdbcUrl;
this.driverProperties = new Properties(properties);
if (username != null)
{
driverProperties.put("user", driverProperties.getProperty("user", username));
}
if (password != null)
{
driverProperties.put("password", driverProperties.getProperty("password", password));
}
if (DriverManager.getDriver(jdbcUrl) == null)
{
throw new IllegalArgumentException("DriverManager was unable to load driver for URL " + jdbcUrl);
}
}
catch (SQLException e)
{
throw new RuntimeException("Unable to get driver for JDBC URL "+ jdbcUrl);
}
}
@Override
public Connection getConnection() throws SQLException
{
return DriverManager.getConnection(jdbcUrl, driverProperties);
}
@Override
public Connection getConnection(String username, String password) throws SQLException
{
return getConnection();
}
@Override
public PrintWriter getLogWriter() throws SQLException
{
return logWriter;
}
@Override
public void setLogWriter(PrintWriter logWriter) throws SQLException
{
this.logWriter = logWriter;
}
@Override
public void setLoginTimeout(int seconds) throws SQLException
{
DriverManager.setLoginTimeout(seconds);
}
@Override
public int getLoginTimeout() throws SQLException
{
return DriverManager.getLoginTimeout();
}
public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException
{
throw new SQLFeatureNotSupportedException();
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException
{
throw new SQLFeatureNotSupportedException();
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException
{
return false;
}
public void shutdown()
{
}
private final String jdbcUrl;
private final Properties driverProperties;
private PrintWriter logWriter;
public DriverDataSource(String jdbcUrl, Properties properties, String username, String password)
{
try {
this.jdbcUrl = jdbcUrl;
this.driverProperties = new Properties(properties);
if (username != null) {
driverProperties.put("user", driverProperties.getProperty("user", username));
}
if (password != null) {
driverProperties.put("password", driverProperties.getProperty("password", password));
}
if (DriverManager.getDriver(jdbcUrl) == null) {
throw new IllegalArgumentException("DriverManager was unable to load driver for URL " + jdbcUrl);
}
}
catch (SQLException e) {
throw new RuntimeException("Unable to get driver for JDBC URL " + jdbcUrl);
}
}
@Override
public Connection getConnection() throws SQLException
{
return DriverManager.getConnection(jdbcUrl, driverProperties);
}
@Override
public Connection getConnection(String username, String password) throws SQLException
{
return getConnection();
}
@Override
public PrintWriter getLogWriter() throws SQLException
{
return logWriter;
}
@Override
public void setLogWriter(PrintWriter logWriter) throws SQLException
{
this.logWriter = logWriter;
}
@Override
public void setLoginTimeout(int seconds) throws SQLException
{
DriverManager.setLoginTimeout(seconds);
}
@Override
public int getLoginTimeout() throws SQLException
{
return DriverManager.getLoginTimeout();
}
public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException
{
throw new SQLFeatureNotSupportedException();
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException
{
throw new SQLFeatureNotSupportedException();
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException
{
return false;
}
public void shutdown()
{
}
}

@ -18,7 +18,6 @@ package com.zaxxer.hikari.util;
import java.lang.reflect.Array;
/**
* Fast list without range checking.
*
@ -26,124 +25,117 @@ import java.lang.reflect.Array;
*/
public final class FastList<T>
{
private T[] elementData;
private int size;
private T[] elementData;
private int size;
/**
* Construct a FastList with a default size of 32.
* @param clazz the Class stored in the collection
*/
@SuppressWarnings("unchecked")
public FastList(Class<?> clazz)
{
this.elementData = (T[]) Array.newInstance(clazz, 32);
}
/**
* Construct a FastList with a default size of 32.
* @param clazz the Class stored in the collection
*/
@SuppressWarnings("unchecked")
public FastList(Class<?> clazz)
{
this.elementData = (T[]) Array.newInstance(clazz, 32);
}
/**
* Construct a FastList with a specfied size.
* @param clazz the Class stored in the collection
* @param capacity the initial size of the FastList
*/
@SuppressWarnings("unchecked")
public FastList(Class<?> clazz, int capacity)
{
this.elementData = (T[]) Array.newInstance(clazz, capacity);
}
/**
* Construct a FastList with a specfied size.
* @param clazz the Class stored in the collection
* @param capacity the initial size of the FastList
*/
@SuppressWarnings("unchecked")
public FastList(Class<?> clazz, int capacity)
{
this.elementData = (T[]) Array.newInstance(clazz, capacity);
}
/**
* Add an element to the tail of the FastList.
*
* @param element the element to add
*/
public void add(T element)
{
try
{
elementData[size++] = element;
}
catch (ArrayIndexOutOfBoundsException e)
{
// overflow-conscious code
final int oldCapacity = elementData.length;
final int newCapacity = oldCapacity << 1;
@SuppressWarnings("unchecked")
final T[] newElementData = (T[]) Array.newInstance(element.getClass(), newCapacity);
System.arraycopy(elementData, 0, newElementData, 0, oldCapacity);
newElementData[size - 1] = element;
elementData = newElementData;
}
}
/**
* Add an element to the tail of the FastList.
*
* @param element the element to add
*/
public void add(T element)
{
try {
elementData[size++] = element;
}
catch (ArrayIndexOutOfBoundsException e) {
// overflow-conscious code
final int oldCapacity = elementData.length;
final int newCapacity = oldCapacity << 1;
@SuppressWarnings("unchecked")
final T[] newElementData = (T[]) Array.newInstance(element.getClass(), newCapacity);
System.arraycopy(elementData, 0, newElementData, 0, oldCapacity);
newElementData[size - 1] = element;
elementData = newElementData;
}
}
/**
* Get the element at the specified index.
*
* @param index the index of the element to get
* @return the element, or ArrayIndexOutOfBounds is thrown if the index is invalid
*/
public T get(int index)
{
return elementData[index];
}
/**
* Get the element at the specified index.
*
* @param index the index of the element to get
* @return the element, or ArrayIndexOutOfBounds is thrown if the index is invalid
*/
public T get(int index)
{
return elementData[index];
}
/**
* This remove method is most efficient when the element being removed
* is the last element. Equality is identity based, not equals() based.
* Only the first matching element is removed.
*
* @return the last element of the list
*/
public T removeLast()
{
T t = elementData[--size];
elementData[size] = null;
return t;
}
/**
* This remove method is most efficient when the element being removed
* is the last element. Equality is identity based, not equals() based.
* Only the first matching element is removed.
*
* @return the last element of the list
*/
public T removeLast()
{
T t = elementData[--size];
elementData[size] = null;
return t;
}
/**
* This remove method is most efficient when the element being removed
* is the last element. Equality is identity based, not equals() based.
* Only the first matching element is removed.
*
* @param element the element to remove
*/
public void remove(T element)
{
for (int index = size - 1; index >= 0; index--)
{
if (element == elementData[index])
{
final int numMoved = size - index - 1;
if (numMoved > 0)
{
System.arraycopy(elementData, index + 1, elementData, index, numMoved);
}
elementData[--size] = null;
break;
/**
* This remove method is most efficient when the element being removed
* is the last element. Equality is identity based, not equals() based.
* Only the first matching element is removed.
*
* @param element the element to remove
*/
public void remove(T element)
{
for (int index = size - 1; index >= 0; index--) {
if (element == elementData[index]) {
final int numMoved = size - index - 1;
if (numMoved > 0) {
System.arraycopy(elementData, index + 1, elementData, index, numMoved);
}
}
}
/**
* Clear the FastList.
*/
public void clear()
{
for (int i = 0; i < size; i++)
{
elementData[i] = null;
}
elementData[--size] = null;
break;
}
}
}
size = 0;
}
/**
* Clear the FastList.
*/
public void clear()
{
for (int i = 0; i < size; i++) {
elementData[i] = null;
}
size = 0;
}
/**
* Get the current number of elements in the FastList.
*
* @return the number of current elements
*/
public int size()
{
return size;
}
/**
* Get the current number of elements in the FastList.
*
* @return the number of current elements
*/
public int size()
{
return size;
}
}

@ -12,131 +12,116 @@ import java.util.concurrent.locks.AbstractQueuedLongSynchronizer;
public final class PoolUtilities
{
public static final boolean IS_JAVA7;
public static final boolean IS_JAVA7;
static
{
boolean b = false;
try
{
b = AbstractQueuedLongSynchronizer.class.getMethod("hasQueuedPredecessors", new Class<?>[0]) != null;
}
catch (Exception e)
{
}
static {
boolean b = false;
try {
b = AbstractQueuedLongSynchronizer.class.getMethod("hasQueuedPredecessors", new Class<?>[0]) != null;
}
catch (Exception e) {
}
IS_JAVA7 = b;
}
IS_JAVA7 = b;
}
public static void quietlyCloseConnection(Connection connection)
{
if (connection != null)
{
try
{
connection.close();
}
catch (SQLException e)
{
return;
}
}
}
public static void quietlyCloseConnection(Connection connection)
{
if (connection != null) {
try {
connection.close();
}
catch (SQLException e) {
return;
}
}
}
/**
* Get the elapsed time in millisecond between the specified start time and now.
*
* @param start the start time
* @return the elapsed milliseconds
*/
public static long elapsedTimeMs(long start)
{
return System.currentTimeMillis() - start;
}
/**
* Get the elapsed time in millisecond between the specified start time and now.
*
* @param start the start time
* @return the elapsed milliseconds
*/
public static long elapsedTimeMs(long start)
{
return System.currentTimeMillis() - start;
}
/**
* Execute the user-specified init SQL.
*
* @param connection the connection to initialize
* @param sql the SQL to execute
* @throws SQLException throws if the init SQL execution fails
*/
public static void executeSqlAutoCommit(Connection connection, String sql) throws SQLException
{
if (sql != null)
{
connection.setAutoCommit(true);
Statement statement = connection.createStatement();
try
{
statement.execute(sql);
}
finally
{
statement.close();
}
}
}
/**
* Execute the user-specified init SQL.
*
* @param connection the connection to initialize
* @param sql the SQL to execute
* @throws SQLException throws if the init SQL execution fails
*/
public static void executeSqlAutoCommit(Connection connection, String sql) throws SQLException
{
if (sql != null) {
connection.setAutoCommit(true);
Statement statement = connection.createStatement();
try {
statement.execute(sql);
}
finally {
statement.close();
}
}
}
public static void quietlySleep(long millis)
{
try
{
Thread.sleep(millis);
}
catch (InterruptedException e)
{
throw new RuntimeException(e);
}
}
public static void quietlySleep(long millis)
{
try {
Thread.sleep(millis);
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
@SuppressWarnings("unchecked")
public static <T> T createInstance(String className, Class<T> clazz, Object...args)
{
if (className == null)
{
return null;
}
@SuppressWarnings("unchecked")
public static <T> T createInstance(String className, Class<T> clazz, Object... args)
{
if (className == null) {
return null;
}
try
{
Class<?> loaded = PoolUtilities.class.getClassLoader().loadClass(className);
try {
Class<?> loaded = PoolUtilities.class.getClassLoader().loadClass(className);
Class<?>[] argClasses = new Class<?>[args.length];
for (int i = 0; i < args.length; i++)
{
argClasses[i] = args[i].getClass();
}
Class<?>[] argClasses = new Class<?>[args.length];
for (int i = 0; i < args.length; i++) {
argClasses[i] = args[i].getClass();
}
if (args.length > 0)
{
Constructor<?> constructor = loaded.getConstructor(argClasses);
return (T) constructor.newInstance(args);
}
if (args.length > 0) {
Constructor<?> constructor = loaded.getConstructor(argClasses);
return (T) constructor.newInstance(args);
}
return (T) loaded.newInstance();
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
return (T) loaded.newInstance();
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
public static ThreadPoolExecutor createThreadPoolExecutor(final int queueSize, final String threadName)
{
ThreadFactory threadFactory = new ThreadFactory() {
public Thread newThread(Runnable r)
{
Thread t = new Thread(r, threadName);
t.setDaemon(true);
return t;
}
};
public static ThreadPoolExecutor createThreadPoolExecutor(final int queueSize, final String threadName)
{
ThreadFactory threadFactory = new ThreadFactory() {
public Thread newThread(Runnable r)
{
Thread t = new Thread(r, threadName);
t.setDaemon(true);
return t;
}
};
int processors = Math.max(1, Runtime.getRuntime().availableProcessors() / 2);
LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(queueSize);
ThreadPoolExecutor executor = new ThreadPoolExecutor(processors, processors, 2, TimeUnit.SECONDS, queue, threadFactory, new ThreadPoolExecutor.DiscardPolicy());
executor.allowCoreThreadTimeOut(true);
return executor;
}
int processors = Math.max(1, Runtime.getRuntime().availableProcessors() / 2);
LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(queueSize);
ThreadPoolExecutor executor = new ThreadPoolExecutor(processors, processors, 2, TimeUnit.SECONDS, queue, threadFactory,
new ThreadPoolExecutor.DiscardPolicy());
executor.allowCoreThreadTimeOut(true);
return executor;
}
}

@ -38,134 +38,111 @@ import com.zaxxer.hikari.HikariConfig;
*/
public final class PropertyBeanSetter
{
private static final Logger LOGGER = LoggerFactory.getLogger(PropertyBeanSetter.class);
private static final Logger LOGGER = LoggerFactory.getLogger(PropertyBeanSetter.class);
public static void setTargetFromProperties(Object target, Properties properties)
{
if (target == null || properties == null)
{
return;
}
public static void setTargetFromProperties(Object target, Properties properties)
{
if (target == null || properties == null) {
return;
}
for (Entry<Object, Object> propEntry : properties.entrySet())
{
String propName = propEntry.getKey().toString();
Object propValue = propEntry.getValue();
for (Entry<Object, Object> propEntry : properties.entrySet()) {
String propName = propEntry.getKey().toString();
Object propValue = propEntry.getValue();
if (target instanceof HikariConfig && propName.startsWith("dataSource."))
{
HikariConfig config = (HikariConfig) target;
config.addDataSourceProperty(propName.substring("dataSource.".length()), propValue);
}
else
{
setProperty(target, propName, propValue);
}
}
}
if (target instanceof HikariConfig && propName.startsWith("dataSource.")) {
HikariConfig config = (HikariConfig) target;
config.addDataSourceProperty(propName.substring("dataSource.".length()), propValue);
}
else {
setProperty(target, propName, propValue);
}
}
}
/**
* Get the bean-style property names for the specified object.
*
* @param targetClass the target object
* @return a set of property names
*/
public static Set<String> getPropertyNames(Class<?> targetClass)
{
HashSet<String> set = new HashSet<String>();
try
{
BeanInfo info = Introspector.getBeanInfo(targetClass);
for (PropertyDescriptor descr : info.getPropertyDescriptors())
{
if (!"class".equals(descr.getName()))
{
set.add(descr.getName());
}
/**
* Get the bean-style property names for the specified object.
*
* @param targetClass the target object
* @return a set of property names
*/
public static Set<String> getPropertyNames(Class<?> targetClass)
{
HashSet<String> set = new HashSet<String>();
try {
BeanInfo info = Introspector.getBeanInfo(targetClass);
for (PropertyDescriptor descr : info.getPropertyDescriptors()) {
if (!"class".equals(descr.getName())) {
set.add(descr.getName());
}
}
return set;
}
catch (IntrospectionException e)
{
throw new RuntimeException(e);
}
}
return set;
}
catch (IntrospectionException e) {
throw new RuntimeException(e);
}
}
public static Object getProperty(String propName, Object target)
{
try
{
String capitalized = "get" + propName.substring(0, 1).toUpperCase() + propName.substring(1);
public static Object getProperty(String propName, Object target)
{
try {
String capitalized = "get" + propName.substring(0, 1).toUpperCase() + propName.substring(1);
Method method = target.getClass().getMethod(capitalized);
return method.invoke(target);
}
catch (Exception e) {
try {
String capitalized = "is" + propName.substring(0, 1).toUpperCase() + propName.substring(1);
Method method = target.getClass().getMethod(capitalized);
return method.invoke(target);
}
catch (Exception e)
{
try
{
String capitalized = "is" + propName.substring(0, 1).toUpperCase() + propName.substring(1);
Method method = target.getClass().getMethod(capitalized);
return method.invoke(target);
}
catch (Exception e2)
{
return null;
}
}
}
}
catch (Exception e2) {
return null;
}
}
}
private static void setProperty(Object target, String propName, Object propValue)
{
String capitalized = "set" + propName.substring(0, 1).toUpperCase() + propName.substring(1);
PropertyDescriptor propertyDescriptor;
try
{
private static void setProperty(Object target, String propName, Object propValue)
{
String capitalized = "set" + propName.substring(0, 1).toUpperCase() + propName.substring(1);
PropertyDescriptor propertyDescriptor;
try {
propertyDescriptor = new PropertyDescriptor(propName, target.getClass(), null, capitalized);
}
catch (IntrospectionException e) {
capitalized = "set" + propName.toUpperCase();
try {
propertyDescriptor = new PropertyDescriptor(propName, target.getClass(), null, capitalized);
}
catch (IntrospectionException e)
{
capitalized = "set" + propName.toUpperCase();
try
{
propertyDescriptor = new PropertyDescriptor(propName, target.getClass(), null, capitalized);
}
catch (IntrospectionException e1)
{
LOGGER.error("Property {} is does not exist on target class {}", propName, target.getClass());
throw new RuntimeException(e);
}
}
try
{
Method writeMethod = propertyDescriptor.getWriteMethod();
Class<?> paramClass = writeMethod.getParameterTypes()[0];
if (paramClass == int.class)
{
writeMethod.invoke(target, Integer.parseInt(propValue.toString()));
}
else if (paramClass == long.class)
{
writeMethod.invoke(target, Long.parseLong(propValue.toString()));
}
else if (paramClass == boolean.class)
{
writeMethod.invoke(target, Boolean.parseBoolean(propValue.toString()));
}
else if (paramClass == String.class)
{
writeMethod.invoke(target, propValue.toString());
}
else
{
writeMethod.invoke(target, propValue);
}
}
catch (Exception e)
{
LOGGER.error("Exception setting property {} on target class {}", propName, target.getClass(), e);
}
catch (IntrospectionException e1) {
LOGGER.error("Property {} is does not exist on target class {}", propName, target.getClass());
throw new RuntimeException(e);
}
}
}
}
try {
Method writeMethod = propertyDescriptor.getWriteMethod();
Class<?> paramClass = writeMethod.getParameterTypes()[0];
if (paramClass == int.class) {
writeMethod.invoke(target, Integer.parseInt(propValue.toString()));
}
else if (paramClass == long.class) {
writeMethod.invoke(target, Long.parseLong(propValue.toString()));
}
else if (paramClass == boolean.class) {
writeMethod.invoke(target, Boolean.parseBoolean(propValue.toString()));
}
else if (paramClass == String.class) {
writeMethod.invoke(target, propValue.toString());
}
else {
writeMethod.invoke(target, propValue);
}
}
catch (Exception e) {
LOGGER.error("Exception setting property {} on target class {}", propName, target.getClass(), e);
throw new RuntimeException(e);
}
}
}

Loading…
Cancel
Save