summaryrefslogtreecommitdiff
path: root/src/main/java/com/zaxxer/hikari/HikariConfig.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/zaxxer/hikari/HikariConfig.java')
-rw-r--r--src/main/java/com/zaxxer/hikari/HikariConfig.java161
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)) {