diff options
Diffstat (limited to 'src/main/java/com/zaxxer/hikari/HikariConfig.java')
-rw-r--r-- | src/main/java/com/zaxxer/hikari/HikariConfig.java | 161 |
1 files changed, 104 insertions, 57 deletions
diff --git a/src/main/java/com/zaxxer/hikari/HikariConfig.java b/src/main/java/com/zaxxer/hikari/HikariConfig.java index ef9f9be..f69f82e 100644 --- a/src/main/java/com/zaxxer/hikari/HikariConfig.java +++ b/src/main/java/com/zaxxer/hikari/HikariConfig.java @@ -16,10 +16,15 @@ package com.zaxxer.hikari; -import static com.zaxxer.hikari.util.UtilityElf.getNullIfEmpty; -import static java.util.concurrent.TimeUnit.MINUTES; -import static java.util.concurrent.TimeUnit.SECONDS; +import com.codahale.metrics.health.HealthCheckRegistry; +import com.zaxxer.hikari.metrics.MetricsTrackerFactory; +import com.zaxxer.hikari.util.PropertyElf; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.sql.DataSource; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -33,18 +38,11 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadFactory; -import javax.naming.InitialContext; -import javax.naming.NamingException; -import javax.sql.DataSource; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.codahale.metrics.MetricRegistry; -import com.codahale.metrics.health.HealthCheckRegistry; -import com.zaxxer.hikari.metrics.MetricsTrackerFactory; -import com.zaxxer.hikari.util.PropertyElf; +import static com.zaxxer.hikari.util.UtilityElf.getNullIfEmpty; +import static java.util.concurrent.TimeUnit.MINUTES; +import static java.util.concurrent.TimeUnit.SECONDS; +@SuppressWarnings({"SameParameterValue", "unused"}) public class HikariConfig implements HikariConfigMXBean { private static final Logger LOGGER = LoggerFactory.getLogger(HikariConfig.class); @@ -55,7 +53,7 @@ public class HikariConfig implements HikariConfigMXBean private static final long MAX_LIFETIME = MINUTES.toMillis(30); private static final int DEFAULT_POOL_SIZE = 10; - private static boolean unitTest; + private static boolean unitTest = false; // Properties changeable at runtime through the MBean // @@ -79,6 +77,7 @@ public class HikariConfig implements HikariConfigMXBean private String jdbcUrl; private String password; private String poolName; + private String schema; private String transactionIsolationName; private String username; private boolean isAutoCommit; @@ -176,8 +175,7 @@ public class HikariConfig implements HikariConfigMXBean /** * Set the SQL query to be executed to test the validity of connections. Using * the JDBC4 <code>Connection.isValid()</code> method to test connection validity can - * be more efficient on some databases and is recommended. See - * {@link HikariConfig#setJdbc4ConnectionTest(boolean)}. + * be more efficient on some databases and is recommended. * * @param connectionTestQuery a SQL query string */ @@ -313,13 +311,32 @@ public class HikariConfig implements HikariConfigMXBean public void setDriverClassName(String driverClassName) { + Class<?> driverClass = null; + try { + driverClass = this.getClass().getClassLoader().loadClass(driverClassName); + LOGGER.debug("Driver class found in the HikariConfig class classloader {}", this.getClass().getClassLoader()); + } catch (ClassNotFoundException e) { + ClassLoader threadContextClassLoader = Thread.currentThread().getContextClassLoader(); + if (threadContextClassLoader != null && threadContextClassLoader != this.getClass().getClassLoader()) { + try { + driverClass = threadContextClassLoader.loadClass(driverClassName); + LOGGER.debug("Driver class found in Thread context class loader {}", threadContextClassLoader); + } catch (ClassNotFoundException e1) { + LOGGER.error("Failed to load class of driverClassName {} in either of HikariConfig class classloader {} or Thread context classloader {}", driverClassName, this.getClass().getClassLoader(), threadContextClassLoader); + } + } else { + LOGGER.error("Failed to load class of driverClassName {} in HikariConfig class classloader {}", driverClassName, this.getClass().getClassLoader()); + } + } + if (driverClass == null) { + throw new RuntimeException("Failed to load class of driverClassName [" + driverClassName + "] in either of HikariConfig class loader or Thread context classloader"); + } try { - Class<?> driverClass = this.getClass().getClassLoader().loadClass(driverClassName); driverClass.newInstance(); this.driverClassName = driverClassName; } catch (Exception e) { - throw new RuntimeException("Failed to load class of driverClassName " + driverClassName, e); + throw new RuntimeException("Failed to instantiate class " + driverClassName, e); } } @@ -410,23 +427,32 @@ public class HikariConfig implements HikariConfigMXBean * or when {@link HikariDataSource} is constructed using the no-arg constructor * and {@link HikariDataSource#getConnection()} is called. * <ul> - * <li>Any value of zero or less will <i>not</i> block the calling thread in the - * case that a connection cannot be obtained. The pool will start and - * continue to try to obtain connections in the background. This can mean - * that callers to {@code DataSource#getConnection()} may encounter - * exceptions.</li> * <li>Any value greater than zero will be treated as a timeout for pool initialization. * The calling thread will be blocked from continuing until a successful connection * to the database, or until the timeout is reached. If the timeout is reached, then - * a {@code PoolInitializationException} will be thrown. + * a {@code PoolInitializationException} will be thrown. </li> + * <li>A value of zero will <i>not</i> prevent the pool from starting in the + * case that a connection cannot be obtained. However, upon start the pool will + * attempt to obtain a connection and validate that the {@code connectionTestQuery} + * and {@code connectionInitSql} are valid. If those validations fail, an exception + * will be thrown. If a connection cannot be obtained, the validation is skipped + * and the the pool will start and continue to try to obtain connections in the + * background. This can mean that callers to {@code DataSource#getConnection()} may + * encounter exceptions. </li> + * <li>A value less than zero will <i>not</i> bypass any connection attempt and + * validation during startup, and therefore the pool will start immediately. The + * pool will continue to try to obtain connections in the background. This can mean + * that callers to {@code DataSource#getConnection()} may encounter exceptions. </li> * </ul> - * Note that this timeout does not override the {@code connectionTimeout} or - * {@code validationTimeout}; they will be honored before this timeout is applied. The - * default value is one millisecond. - * + * Note that if this timeout value is greater than or equal to zero (0), and therefore an + * initial connection validation is performed, this timeout does not override the + * {@code connectionTimeout} or {@code validationTimeout}; they will be honored before this + * timeout is applied. The default value is one millisecond. + * * @param initializationFailTimeout the number of milliseconds before the - * pool initialization fails, or 0 or less to skip the initialization - * check. + * pool initialization fails, or 0 to validate connection setup but continue with + * pool start, or less than zero to skip all initialization checks and start the + * pool without delay. */ public void setInitializationFailTimeout(long initializationFailTimeout) { @@ -457,8 +483,8 @@ public class HikariConfig implements HikariConfigMXBean public void setInitializationFailFast(boolean failFast) { LOGGER.warn("The initializationFailFast propery is deprecated, see initializationFailTimeout"); - - initializationFailTimeout = (failFast ? 1 : 0); + + initializationFailTimeout = (failFast ? 1 : -1); } public boolean isIsolateInternalQueries() @@ -519,24 +545,31 @@ public class HikariConfig implements HikariConfigMXBean } if (metricRegistry != null) { - if (metricRegistry instanceof String) { - try { - InitialContext initCtx = new InitialContext(); - metricRegistry = initCtx.lookup((String) metricRegistry); - } - catch (NamingException e) { - throw new IllegalArgumentException(e); - } - } + metricRegistry = getObjectOrPerformJndiLookup(metricRegistry); - if (!(metricRegistry instanceof MetricRegistry)) { - throw new IllegalArgumentException("Class must be an instance of com.codahale.metrics.MetricRegistry"); + if (!(metricRegistry.getClass().getName().contains("MetricRegistry")) + && !(metricRegistry.getClass().getName().contains("MeterRegistry"))) { + throw new IllegalArgumentException("Class must be instance of com.codahale.metrics.MetricRegistry or io.micrometer.core.instrument.MeterRegistry"); } } this.metricRegistry = metricRegistry; } + private Object getObjectOrPerformJndiLookup(Object object) + { + if (object instanceof String) { + try { + InitialContext initCtx = new InitialContext(); + return initCtx.lookup((String) object); + } + catch (NamingException e) { + throw new IllegalArgumentException(e); + } + } + return object; + } + /** * Get the Codahale HealthCheckRegistry, could be null. * @@ -555,15 +588,7 @@ public class HikariConfig implements HikariConfigMXBean public void setHealthCheckRegistry(Object healthCheckRegistry) { if (healthCheckRegistry != null) { - if (healthCheckRegistry instanceof String) { - try { - InitialContext initCtx = new InitialContext(); - healthCheckRegistry = initCtx.lookup((String) healthCheckRegistry); - } - catch (NamingException e) { - throw new IllegalArgumentException(e); - } - } + healthCheckRegistry = getObjectOrPerformJndiLookup(healthCheckRegistry); if (!(healthCheckRegistry instanceof HealthCheckRegistry)) { throw new IllegalArgumentException("Class must be an instance of com.codahale.metrics.health.HealthCheckRegistry"); @@ -748,13 +773,29 @@ public class HikariConfig implements HikariConfigMXBean { this.scheduledExecutor = executor; } - + public String getTransactionIsolation() { return transactionIsolationName; } /** + * Get the default schema name to be set on connections. + * + * @return the default schema name + */ + public String getSchema() { + return schema; + } + + /** + * Set the default schema name to be set on connections. + */ + public void setSchema(String schema) { + this.schema = schema; + } + + /** * Set the default transaction isolation level. The specified value is the * constant name from the <code>Connection</code> class, eg. * <code>TRANSACTION_REPEATABLE_READ</code>. @@ -807,6 +848,7 @@ public class HikariConfig implements HikariConfigMXBean this.threadFactory = threadFactory; } + @SuppressWarnings("StatementWithEmptyBody") public void validate() { if (poolName == null) { @@ -843,7 +885,8 @@ public class HikariConfig implements HikariConfigMXBean LOGGER.warn("{} - using dataSourceClassName and ignoring jdbcUrl.", poolName); } } - else if (jdbcUrl != null) { + else if (jdbcUrl != null || dataSourceJndiName != null) { + // ok } else if (driverClassName != null) { LOGGER.error("{} - jdbcUrl is required with driverClassName.", poolName); @@ -904,6 +947,7 @@ public class HikariConfig implements HikariConfigMXBean } } + @SuppressWarnings("StatementWithEmptyBody") private void logConfiguration() { LOGGER.debug("{} - configuration:", poolName); @@ -926,6 +970,9 @@ public class HikariConfig implements HikariConfigMXBean else if (prop.matches("scheduledExecutorService|threadFactory") && value == null) { value = "internal"; } + else if (prop.contains("jdbcUrl") && value instanceof String) { + value = ((String)value).replaceAll("([?&;]password=)[^&#;]*(.*)", "$1<masked>$2"); + } else if (prop.contains("password")) { value = "<masked>"; } @@ -938,12 +985,12 @@ public class HikariConfig implements HikariConfigMXBean LOGGER.debug((prop + "................................................").substring(0, 32) + value); } catch (Exception e) { - continue; + // continue } } } - protected void loadProperties(String propertyFileName) + private void loadProperties(String propertyFileName) { final File propFile = new File(propertyFileName); try (final InputStream is = propFile.isFile() ? new FileInputStream(propFile) : this.getClass().getResourceAsStream(propertyFileName)) { |