View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.dbcp2;
18  
19  import java.sql.Connection;
20  import java.sql.SQLException;
21  import java.sql.Statement;
22  import java.time.Duration;
23  import java.util.Collection;
24  import java.util.Objects;
25  import java.util.concurrent.atomic.AtomicLong;
26  
27  import javax.management.MalformedObjectNameException;
28  import javax.management.ObjectName;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.apache.commons.pool2.DestroyMode;
33  import org.apache.commons.pool2.KeyedObjectPool;
34  import org.apache.commons.pool2.ObjectPool;
35  import org.apache.commons.pool2.PooledObject;
36  import org.apache.commons.pool2.PooledObjectFactory;
37  import org.apache.commons.pool2.impl.DefaultPooledObject;
38  import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
39  import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
40  
41  /**
42   * A {@link PooledObjectFactory} that creates {@link PoolableConnection}s.
43   *
44   * @since 2.0
45   */
46  public class PoolableConnectionFactory implements PooledObjectFactory<PoolableConnection> {
47  
48      private static final Log log = LogFactory.getLog(PoolableConnectionFactory.class);
49  
50      /**
51       * Internal constant to indicate the level is not set.
52       */
53      static final int UNKNOWN_TRANSACTION_ISOLATION = -1;
54  
55      private final ConnectionFactory connectionFactory;
56  
57      private final ObjectName dataSourceJmxObjectName;
58  
59      private volatile String validationQuery;
60  
61      private volatile Duration validationQueryTimeoutDuration = Duration.ofSeconds(-1);
62  
63      private Collection<String> connectionInitSqls;
64  
65      private Collection<String> disconnectionSqlCodes;
66  
67      private boolean fastFailValidation = true;
68  
69      private volatile ObjectPool<PoolableConnection> pool;
70  
71      private Boolean defaultReadOnly;
72  
73      private Boolean defaultAutoCommit;
74  
75      private boolean autoCommitOnReturn = true;
76  
77      private boolean rollbackOnReturn = true;
78  
79      private int defaultTransactionIsolation = UNKNOWN_TRANSACTION_ISOLATION;
80  
81      private String defaultCatalog;
82  
83      private String defaultSchema;
84  
85      private boolean cacheState;
86  
87      private boolean poolStatements;
88  
89      private boolean clearStatementPoolOnReturn;
90  
91      private int maxOpenPreparedStatements = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL_PER_KEY;
92  
93      private Duration maxConnDuration = Duration.ofMillis(-1);
94  
95      private final AtomicLong connectionIndex = new AtomicLong();
96  
97      private Duration defaultQueryTimeoutDuration;
98  
99      /**
100      * Creates a new {@code PoolableConnectionFactory}.
101      *
102      * @param connFactory
103      *            the {@link ConnectionFactory} from which to obtain base {@link Connection}s
104      * @param dataSourceJmxObjectName
105      *            The JMX object name, may be null.
106      */
107     public PoolableConnectionFactory(final ConnectionFactory connFactory, final ObjectName dataSourceJmxObjectName) {
108         this.connectionFactory = connFactory;
109         this.dataSourceJmxObjectName = dataSourceJmxObjectName;
110     }
111 
112     @Override
113     public void activateObject(final PooledObject<PoolableConnection> p) throws SQLException {
114 
115         validateLifetime(p);
116 
117         final PoolableConnection pConnection = p.getObject();
118         pConnection.activate();
119 
120         if (defaultAutoCommit != null && pConnection.getAutoCommit() != defaultAutoCommit) {
121             pConnection.setAutoCommit(defaultAutoCommit);
122         }
123         if (defaultTransactionIsolation != UNKNOWN_TRANSACTION_ISOLATION
124                 && pConnection.getTransactionIsolation() != defaultTransactionIsolation) {
125             pConnection.setTransactionIsolation(defaultTransactionIsolation);
126         }
127         if (defaultReadOnly != null && pConnection.isReadOnly() != defaultReadOnly) {
128             pConnection.setReadOnly(defaultReadOnly);
129         }
130         if (defaultCatalog != null && !defaultCatalog.equals(pConnection.getCatalog())) {
131             pConnection.setCatalog(defaultCatalog);
132         }
133         if (defaultSchema != null && !defaultSchema.equals(Jdbc41Bridge.getSchema(pConnection))) {
134             Jdbc41Bridge.setSchema(pConnection, defaultSchema);
135         }
136         pConnection.setDefaultQueryTimeout(defaultQueryTimeoutDuration);
137     }
138 
139     @Override
140     public void destroyObject(final PooledObject<PoolableConnection> p) throws SQLException {
141         p.getObject().reallyClose();
142     }
143 
144     /**
145      * @since 2.9.0
146      */
147     @Override
148     public void destroyObject(final PooledObject<PoolableConnection> p, final DestroyMode mode) throws SQLException {
149         if (mode == DestroyMode.ABANDONED) {
150             p.getObject().getInnermostDelegate().abort(Runnable::run);
151         } else {
152             p.getObject().reallyClose();
153         }
154     }
155 
156     /**
157      * Gets the cache state.
158      *
159      * @return The cache state.
160      * @since 2.6.0.
161      */
162     public boolean getCacheState() {
163         return cacheState;
164     }
165 
166     /**
167      * Gets the connection factory.
168      *
169      * @return The connection factory.
170      * @since 2.6.0.
171      */
172     public ConnectionFactory getConnectionFactory() {
173         return connectionFactory;
174     }
175 
176     protected AtomicLong getConnectionIndex() {
177         return connectionIndex;
178     }
179 
180     /**
181      * @return The collection of initialization SQL statements.
182      * @since 2.6.0
183      */
184     public Collection<String> getConnectionInitSqls() {
185         return connectionInitSqls;
186     }
187 
188     /**
189      * @return The data source JMX ObjectName
190      * @since 2.6.0.
191      */
192     public ObjectName getDataSourceJmxName() {
193         return dataSourceJmxObjectName;
194     }
195 
196     /**
197      * @return The data source JMS ObjectName.
198      * @since 2.6.0
199      */
200     public ObjectName getDataSourceJmxObjectName() {
201         return dataSourceJmxObjectName;
202     }
203 
204     /**
205      * @return Default auto-commit value.
206      * @since 2.6.0
207      */
208     public Boolean getDefaultAutoCommit() {
209         return defaultAutoCommit;
210     }
211 
212     /**
213      * @return Default catalog.
214      * @since 2.6.0
215      */
216     public String getDefaultCatalog() {
217         return defaultCatalog;
218     }
219 
220     /**
221      * @return Default query timeout in seconds.
222      * @deprecated Use {@link #getDefaultQueryTimeoutDuration()}.
223      */
224     @Deprecated
225     public Integer getDefaultQueryTimeout() {
226         return getDefaultQueryTimeoutSeconds();
227     }
228 
229     /**
230      * Gets the default query timeout Duration.
231      *
232      * @return Default query timeout Duration.
233      * @since 2.10.0
234      */
235     public Duration getDefaultQueryTimeoutDuration() {
236         return defaultQueryTimeoutDuration;
237     }
238 
239     /**
240      * @return Default query timeout in seconds.
241      * @since 2.6.0
242      * @deprecated Use {@link #getDefaultQueryTimeoutDuration()}.
243      */
244     @Deprecated
245     public Integer getDefaultQueryTimeoutSeconds() {
246         return defaultQueryTimeoutDuration == null ? null : (int) defaultQueryTimeoutDuration.getSeconds();
247     }
248 
249     /**
250      * @return Default read-only-value.
251      * @since 2.6.0
252      */
253     public Boolean getDefaultReadOnly() {
254         return defaultReadOnly;
255     }
256 
257     /**
258      * @return Default schema.
259      * @since 2.6.0
260      */
261     public String getDefaultSchema() {
262         return defaultSchema;
263     }
264 
265     /**
266      * @return Default transaction isolation.
267      * @since 2.6.0
268      */
269     public int getDefaultTransactionIsolation() {
270         return defaultTransactionIsolation;
271     }
272 
273     /**
274      * SQL_STATE codes considered to signal fatal conditions.
275      * <p>
276      * Overrides the defaults in {@link Utils#getDisconnectionSqlCodes()} (plus anything starting with
277      * {@link Utils#DISCONNECTION_SQL_CODE_PREFIX}). If this property is non-null and {@link #isFastFailValidation()} is
278      * {@code true}, whenever connections created by this factory generate exceptions with SQL_STATE codes in this list,
279      * they will be marked as "fatally disconnected" and subsequent validations will fail fast (no attempt at isValid or
280      * validation query).
281      * </p>
282      * <p>
283      * If {@link #isFastFailValidation()} is {@code false} setting this property has no effect.
284      * </p>
285      *
286      * @return SQL_STATE codes overriding defaults
287      * @since 2.1
288      */
289     public Collection<String> getDisconnectionSqlCodes() {
290         return disconnectionSqlCodes;
291     }
292 
293     /**
294      * Gets the Maximum connection duration.
295      *
296      * @return Maximum connection duration.
297      * @since 2.10.0
298      */
299     public Duration getMaxConnDuration() {
300         return maxConnDuration;
301     }
302 
303     /**
304      * Gets the Maximum connection lifetime in milliseconds.
305      *
306      * @return Maximum connection lifetime in milliseconds.
307      * @since 2.6.0
308      */
309     public long getMaxConnLifetimeMillis() {
310         return maxConnDuration.toMillis();
311     }
312 
313     protected int getMaxOpenPreparedStatements() {
314         return maxOpenPreparedStatements;
315     }
316     /**
317      * Returns the {@link ObjectPool} in which {@link Connection}s are pooled.
318      *
319      * @return the connection pool
320      */
321     public synchronized ObjectPool<PoolableConnection> getPool() {
322         return pool;
323     }
324     /**
325      * @return Whether to pool statements.
326      * @since 2.6.0.
327      */
328     public boolean getPoolStatements() {
329         return poolStatements;
330     }
331     /**
332      * @return Validation query.
333      * @since 2.6.0
334      */
335     public String getValidationQuery() {
336         return validationQuery;
337     }
338 
339     /**
340      * Gets the query timeout in seconds.
341      *
342      * @return Validation query timeout in seconds.
343      * @since 2.10.0
344      */
345     public Duration getValidationQueryTimeoutDuration() {
346         return validationQueryTimeoutDuration;
347     }
348 
349     /**
350      * Gets the query timeout in seconds.
351      *
352      * @return Validation query timeout in seconds.
353      * @since 2.6.0
354      * @deprecated Use {@link #getValidationQueryTimeoutDuration()}.
355      */
356     @Deprecated
357     public int getValidationQueryTimeoutSeconds() {
358         return (int) validationQueryTimeoutDuration.getSeconds();
359     }
360 
361     protected void initializeConnection(final Connection conn) throws SQLException {
362         final Collection<String> sqls = connectionInitSqls;
363         if (conn.isClosed()) {
364             throw new SQLException("initializeConnection: connection closed");
365         }
366         if (!Utils.isEmpty(sqls)) {
367             try (Statement statement = conn.createStatement()) {
368                 for (final String sql : sqls) {
369                     statement.execute(Objects.requireNonNull(sql, "null connectionInitSqls element"));
370                 }
371             }
372         }
373     }
374 
375     /**
376      * @return Whether to auto-commit on return.
377      * @since 2.6.0
378      */
379     public boolean isAutoCommitOnReturn() {
380         return autoCommitOnReturn;
381     }
382 
383     /**
384      * @return Whether to auto-commit on return.
385      * @deprecated Use {@link #isAutoCommitOnReturn()}.
386      */
387     @Deprecated
388     public boolean isEnableAutoCommitOnReturn() {
389         return autoCommitOnReturn;
390     }
391 
392     /**
393      * True means that validation will fail immediately for connections that have previously thrown SQLExceptions with
394      * SQL_STATE indicating fatal disconnection errors.
395      *
396      * @return true if connections created by this factory will fast fail validation.
397      * @see #setDisconnectionSqlCodes(Collection)
398      * @since 2.1
399      * @since 2.5.0 Defaults to true, previous versions defaulted to false.
400      */
401     public boolean isFastFailValidation() {
402         return fastFailValidation;
403     }
404 
405     /**
406      * @return Whether to rollback on return.
407      */
408     public boolean isRollbackOnReturn() {
409         return rollbackOnReturn;
410     }
411 
412     @Override
413     public PooledObject<PoolableConnection> makeObject() throws SQLException {
414         Connection conn = connectionFactory.createConnection();
415         if (conn == null) {
416             throw new IllegalStateException("Connection factory returned null from createConnection");
417         }
418         try {
419             initializeConnection(conn);
420         } catch (final SQLException e) {
421             // Make sure the connection is closed
422             Utils.closeQuietly((AutoCloseable) conn);
423             // Rethrow original exception so it is visible to caller
424             throw e;
425         }
426 
427         final long connIndex = connectionIndex.getAndIncrement();
428 
429         if (poolStatements) {
430             conn = new PoolingConnection(conn);
431             final GenericKeyedObjectPoolConfig<DelegatingPreparedStatement> config = new GenericKeyedObjectPoolConfig<>();
432             config.setMaxTotalPerKey(-1);
433             config.setBlockWhenExhausted(false);
434             config.setMaxWait(Duration.ZERO);
435             config.setMaxIdlePerKey(1);
436             config.setMaxTotal(maxOpenPreparedStatements);
437             if (dataSourceJmxObjectName != null) {
438                 final StringBuilder base = new StringBuilder(dataSourceJmxObjectName.toString());
439                 base.append(Constants.JMX_CONNECTION_BASE_EXT);
440                 base.append(connIndex);
441                 config.setJmxNameBase(base.toString());
442                 config.setJmxNamePrefix(Constants.JMX_STATEMENT_POOL_PREFIX);
443             } else {
444                 config.setJmxEnabled(false);
445             }
446             final PoolingConnection poolingConn = (PoolingConnection) conn;
447             final KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> stmtPool = new GenericKeyedObjectPool<>(poolingConn, config);
448             poolingConn.setStatementPool(stmtPool);
449             poolingConn.setClearStatementPoolOnReturn(clearStatementPoolOnReturn);
450             poolingConn.setCacheState(cacheState);
451         }
452 
453         // Register this connection with JMX
454         final ObjectName connJmxName;
455         if (dataSourceJmxObjectName == null) {
456             connJmxName = null;
457         } else {
458             final String name = dataSourceJmxObjectName.toString() + Constants.JMX_CONNECTION_BASE_EXT + connIndex;
459             try {
460                 connJmxName = new ObjectName(name);
461             } catch (final MalformedObjectNameException e) {
462                 Utils.closeQuietly((AutoCloseable) conn);
463                 throw new SQLException(name, e);
464             }
465         }
466 
467         final PoolableConnection pc = new PoolableConnection(conn, pool, connJmxName, disconnectionSqlCodes, fastFailValidation);
468         pc.setCacheState(cacheState);
469 
470         return new DefaultPooledObject<>(pc);
471     }
472 
473     @Override
474     public void passivateObject(final PooledObject<PoolableConnection> p) throws SQLException {
475 
476         validateLifetime(p);
477 
478         final PoolableConnection conn = p.getObject();
479         Boolean connAutoCommit = null;
480         if (rollbackOnReturn) {
481             connAutoCommit = conn.getAutoCommit();
482             if (!connAutoCommit && !conn.isReadOnly()) {
483                 conn.rollback();
484             }
485         }
486 
487         conn.clearWarnings();
488 
489         // DBCP-97 / DBCP-399 / DBCP-351 Idle connections in the pool should
490         // have autoCommit enabled
491         if (autoCommitOnReturn) {
492             if (connAutoCommit == null) {
493                 connAutoCommit = conn.getAutoCommit();
494             }
495             if (!connAutoCommit) {
496                 conn.setAutoCommit(true);
497             }
498         }
499 
500         conn.passivate();
501     }
502 
503     public void setAutoCommitOnReturn(final boolean autoCommitOnReturn) {
504         this.autoCommitOnReturn = autoCommitOnReturn;
505     }
506 
507     public void setCacheState(final boolean cacheState) {
508         this.cacheState = cacheState;
509     }
510 
511     /**
512      * Sets whether the pool of statements (which was enabled with {@link #setPoolStatements(boolean)}) should
513      * be cleared when the connection is returned to its pool. Default is false.
514      *
515      * @param clearStatementPoolOnReturn clear or not
516      * @since 2.8.0
517      */
518     public void setClearStatementPoolOnReturn(final boolean clearStatementPoolOnReturn) {
519         this.clearStatementPoolOnReturn = clearStatementPoolOnReturn;
520     }
521 
522     /**
523      * Sets the SQL statements I use to initialize newly created {@link Connection}s. Using {@code null} turns off
524      * connection initialization.
525      *
526      * @param connectionInitSqls
527      *            SQL statement to initialize {@link Connection}s.
528      */
529     public void setConnectionInitSql(final Collection<String> connectionInitSqls) {
530         this.connectionInitSqls = connectionInitSqls;
531     }
532     /**
533      * Sets the default "auto commit" setting for borrowed {@link Connection}s
534      *
535      * @param defaultAutoCommit
536      *            the default "auto commit" setting for borrowed {@link Connection}s
537      */
538     public void setDefaultAutoCommit(final Boolean defaultAutoCommit) {
539         this.defaultAutoCommit = defaultAutoCommit;
540     }
541 
542     /**
543      * Sets the default "catalog" setting for borrowed {@link Connection}s
544      *
545      * @param defaultCatalog
546      *            the default "catalog" setting for borrowed {@link Connection}s
547      */
548     public void setDefaultCatalog(final String defaultCatalog) {
549         this.defaultCatalog = defaultCatalog;
550     }
551 
552     /**
553      * Sets the query timeout Duration.
554      *
555      * @param defaultQueryTimeoutDuration the query timeout Duration.
556      * @since 2.10.0
557      */
558     public void setDefaultQueryTimeout(final Duration defaultQueryTimeoutDuration) {
559         this.defaultQueryTimeoutDuration = defaultQueryTimeoutDuration;
560     }
561 
562     /**
563      * Sets the query timeout in seconds.
564      *
565      * @param defaultQueryTimeoutSeconds the query timeout in seconds.
566      * @deprecated Use {@link #setDefaultQueryTimeout(Duration)}.
567      */
568     @Deprecated
569     public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) {
570         this.defaultQueryTimeoutDuration = defaultQueryTimeoutSeconds == null ? null : Duration.ofSeconds(defaultQueryTimeoutSeconds);
571     }
572 
573     /**
574      * Sets the default "read only" setting for borrowed {@link Connection}s
575      *
576      * @param defaultReadOnly
577      *            the default "read only" setting for borrowed {@link Connection}s
578      */
579     public void setDefaultReadOnly(final Boolean defaultReadOnly) {
580         this.defaultReadOnly = defaultReadOnly;
581     }
582 
583     /**
584      * Sets the default "schema" setting for borrowed {@link Connection}s
585      *
586      * @param defaultSchema
587      *            the default "schema" setting for borrowed {@link Connection}s
588      * @since 2.5.0
589      */
590     public void setDefaultSchema(final String defaultSchema) {
591         this.defaultSchema = defaultSchema;
592     }
593 
594     /**
595      * Sets the default "Transaction Isolation" setting for borrowed {@link Connection}s
596      *
597      * @param defaultTransactionIsolation
598      *            the default "Transaction Isolation" setting for returned {@link Connection}s
599      */
600     public void setDefaultTransactionIsolation(final int defaultTransactionIsolation) {
601         this.defaultTransactionIsolation = defaultTransactionIsolation;
602     }
603 
604     /**
605      * @param disconnectionSqlCodes
606      *            The disconnection SQL codes.
607      * @see #getDisconnectionSqlCodes()
608      * @since 2.1
609      */
610     public void setDisconnectionSqlCodes(final Collection<String> disconnectionSqlCodes) {
611         this.disconnectionSqlCodes = disconnectionSqlCodes;
612     }
613 
614     /**
615      * @param autoCommitOnReturn Whether to auto-commit on return.
616      * @deprecated Use {@link #setAutoCommitOnReturn(boolean)}.
617      */
618     @Deprecated
619     public void setEnableAutoCommitOnReturn(final boolean autoCommitOnReturn) {
620         this.autoCommitOnReturn = autoCommitOnReturn;
621     }
622 
623     /**
624      * @see #isFastFailValidation()
625      * @param fastFailValidation
626      *            true means connections created by this factory will fast fail validation
627      * @since 2.1
628      */
629     public void setFastFailValidation(final boolean fastFailValidation) {
630         this.fastFailValidation = fastFailValidation;
631     }
632 
633     /**
634      * Sets the maximum lifetime in milliseconds of a connection after which the connection will always fail activation,
635      * passivation and validation. A value of zero or less indicates an infinite lifetime. The default value is -1.
636      *
637      * @param maxConnDuration
638      *            The maximum lifetime in milliseconds.
639      * @since 2.10.0
640      */
641     public void setMaxConn(final Duration maxConnDuration) {
642         this.maxConnDuration = maxConnDuration;
643     }
644 
645     /**
646      * Sets the maximum lifetime in milliseconds of a connection after which the connection will always fail activation,
647      * passivation and validation. A value of zero or less indicates an infinite lifetime. The default value is -1.
648      *
649      * @param maxConnLifetimeMillis
650      *            The maximum lifetime in milliseconds.
651      * @deprecated Use {@link #setMaxConn(Duration)}.
652      */
653     @Deprecated
654     public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
655         this.maxConnDuration = Duration.ofMillis(maxConnLifetimeMillis);
656     }
657 
658     /**
659      * Sets the maximum number of open prepared statements.
660      *
661      * @param maxOpenPreparedStatements
662      *            The maximum number of open prepared statements.
663      */
664     public void setMaxOpenPreparedStatements(final int maxOpenPreparedStatements) {
665         this.maxOpenPreparedStatements = maxOpenPreparedStatements;
666     }
667 
668     /**
669      * Deprecated due to typo in method name.
670      *
671      * @param maxOpenPreparedStatements
672      *            The maximum number of open prepared statements.
673      * @deprecated Use {@link #setMaxOpenPreparedStatements(int)}.
674      */
675     @Deprecated // Due to typo in method name.
676     public void setMaxOpenPrepatedStatements(final int maxOpenPreparedStatements) {
677         setMaxOpenPreparedStatements(maxOpenPreparedStatements);
678     }
679 
680     /**
681      * Sets the {@link ObjectPool} in which to pool {@link Connection}s.
682      *
683      * @param pool
684      *            the {@link ObjectPool} in which to pool those {@link Connection}s
685      */
686     public synchronized void setPool(final ObjectPool<PoolableConnection> pool) {
687         if (null != this.pool && pool != this.pool) {
688             Utils.closeQuietly(this.pool);
689         }
690         this.pool = pool;
691     }
692 
693     public void setPoolStatements(final boolean poolStatements) {
694         this.poolStatements = poolStatements;
695     }
696 
697     public void setRollbackOnReturn(final boolean rollbackOnReturn) {
698         this.rollbackOnReturn = rollbackOnReturn;
699     }
700 
701     /**
702      * Sets the query I use to {@link #validateObject validate} {@link Connection}s. Should return at least one row. If
703      * not specified, {@link Connection#isValid(int)} will be used to validate connections.
704      *
705      * @param validationQuery
706      *            a query to use to {@link #validateObject validate} {@link Connection}s.
707      */
708     public void setValidationQuery(final String validationQuery) {
709         this.validationQuery = validationQuery;
710     }
711 
712     /**
713      * Sets the validation query timeout, the amount of time, that connection validation will wait for a response from the
714      * database when executing a validation query. Use a value less than or equal to 0 for no timeout.
715      *
716      * @param validationQueryTimeoutDuration new validation query timeout duration.
717      * @since 2.10.0
718      */
719     public void setValidationQueryTimeout(final Duration validationQueryTimeoutDuration) {
720         this.validationQueryTimeoutDuration = validationQueryTimeoutDuration;
721     }
722 
723     /**
724      * Sets the validation query timeout, the amount of time, in seconds, that connection validation will wait for a
725      * response from the database when executing a validation query. Use a value less than or equal to 0 for no timeout.
726      *
727      * @param validationQueryTimeoutSeconds
728      *            new validation query timeout value in seconds
729      * @deprecated {@link #setValidationQueryTimeout(Duration)}.
730      */
731     @Deprecated
732     public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) {
733         this.validationQueryTimeoutDuration = Duration.ofSeconds(validationQueryTimeoutSeconds);
734     }
735 
736     /**
737      * Validates the given connection if it is open.
738      *
739      * @param conn the connection to validate.
740      * @throws SQLException if the connection is closed or validate fails.
741      */
742     public void validateConnection(final PoolableConnection conn) throws SQLException {
743         if (conn.isClosed()) {
744             throw new SQLException("validateConnection: connection closed");
745         }
746         conn.validate(validationQuery, validationQueryTimeoutDuration);
747     }
748 
749     private void validateLifetime(final PooledObject<PoolableConnection> p) throws LifetimeExceededException {
750         Utils.validateLifetime(p, maxConnDuration);
751     }
752 
753     @Override
754     public boolean validateObject(final PooledObject<PoolableConnection> p) {
755         try {
756             validateLifetime(p);
757             validateConnection(p.getObject());
758             return true;
759         } catch (final Exception e) {
760             if (log.isDebugEnabled()) {
761                 log.debug(Utils.getMessage("poolableConnectionFactory.validateObject.fail"), e);
762             }
763             return false;
764         }
765     }
766 }