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    *      https://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 Collection<String> disconnectionIgnoreSqlCodes;
68  
69      private volatile boolean fastFailValidation = true;
70  
71      private volatile ObjectPool<PoolableConnection> pool;
72  
73      private Boolean defaultReadOnly;
74  
75      private Boolean defaultAutoCommit;
76  
77      private volatile boolean autoCommitOnReturn = true;
78  
79      private volatile boolean rollbackOnReturn = true;
80  
81      private volatile int defaultTransactionIsolation = UNKNOWN_TRANSACTION_ISOLATION;
82  
83      private String defaultCatalog;
84  
85      private String defaultSchema;
86  
87      private volatile boolean cacheState;
88  
89      private volatile boolean poolStatements;
90  
91      private volatile boolean clearStatementPoolOnReturn;
92  
93      private volatile int maxOpenPreparedStatements = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL_PER_KEY;
94  
95      private Duration maxConnDuration = Duration.ofMillis(-1);
96  
97      private final AtomicLong connectionIndex = new AtomicLong();
98  
99      private Duration defaultQueryTimeoutDuration;
100 
101     /**
102      * Creates a new {@link PoolableConnectionFactory}.
103      *
104      * @param connFactory
105      *            the {@link ConnectionFactory} from which to obtain base {@link Connection}s
106      * @param dataSourceJmxObjectName
107      *            The JMX object name, may be null.
108      */
109     public PoolableConnectionFactory(final ConnectionFactory connFactory, final ObjectName dataSourceJmxObjectName) {
110         this.connectionFactory = connFactory;
111         this.dataSourceJmxObjectName = dataSourceJmxObjectName;
112     }
113 
114     @Override
115     public void activateObject(final PooledObject<PoolableConnection> p) throws SQLException {
116         validateLifetime(p);
117         final PoolableConnection poolableConnection = p.getObject();
118         poolableConnection.activate();
119         if (defaultAutoCommit != null && poolableConnection.getAutoCommit() != defaultAutoCommit) {
120             poolableConnection.setAutoCommit(defaultAutoCommit);
121         }
122         if (defaultTransactionIsolation != UNKNOWN_TRANSACTION_ISOLATION && poolableConnection.getTransactionIsolation() != defaultTransactionIsolation) {
123             poolableConnection.setTransactionIsolation(defaultTransactionIsolation);
124         }
125         if (defaultReadOnly != null && poolableConnection.isReadOnly() != defaultReadOnly) {
126             poolableConnection.setReadOnly(defaultReadOnly);
127         }
128         if (defaultCatalog != null && !defaultCatalog.equals(poolableConnection.getCatalog())) {
129             poolableConnection.setCatalog(defaultCatalog);
130         }
131         if (defaultSchema != null && !defaultSchema.equals(Jdbc41Bridge.getSchema(poolableConnection))) {
132             Jdbc41Bridge.setSchema(poolableConnection, defaultSchema);
133         }
134         poolableConnection.setDefaultQueryTimeout(defaultQueryTimeoutDuration);
135     }
136 
137     @Override
138     public void destroyObject(final PooledObject<PoolableConnection> p) throws SQLException {
139         p.getObject().reallyClose();
140     }
141 
142     /**
143      * @since 2.9.0
144      */
145     @Override
146     public void destroyObject(final PooledObject<PoolableConnection> p, final DestroyMode mode) throws SQLException {
147         if (mode == DestroyMode.ABANDONED) {
148             Jdbc41Bridge.abort(p.getObject().getInnermostDelegate(), Runnable::run);
149         } else {
150             p.getObject().reallyClose();
151         }
152     }
153 
154     /**
155      * Gets the cache state to propagate in {@link #makeObject()}.
156      *
157      * @return The cache state.
158      * @since 2.6.0.
159      */
160     public boolean getCacheState() {
161         return cacheState;
162     }
163 
164     /**
165      * Gets the connection factory.
166      *
167      * @return The connection factory.
168      * @since 2.6.0.
169      */
170     public ConnectionFactory getConnectionFactory() {
171         return connectionFactory;
172     }
173 
174     /**
175      * Gets how many connections were created in {@link #makeObject()}.
176      *
177      * @return the connection count.
178      */
179     protected AtomicLong getConnectionIndex() {
180         return connectionIndex;
181     }
182 
183     /**
184      * Gets the collection of initialization SQL statements.
185      *
186      * @return The collection of initialization SQL statements.
187      * @since 2.6.0
188      */
189     public Collection<String> getConnectionInitSqls() {
190         return connectionInitSqls;
191     }
192 
193     /**
194      * Gets data source JMX ObjectName.
195      *
196      * @return The data source JMX ObjectName.
197      * @since 2.6.0.
198      */
199     public ObjectName getDataSourceJmxName() {
200         return dataSourceJmxObjectName;
201     }
202 
203     /**
204      * Gets the data source JMX ObjectName.
205      *
206      * @return The data source JMX ObjectName.
207      * @since 2.6.0
208      */
209     public ObjectName getDataSourceJmxObjectName() {
210         return dataSourceJmxObjectName;
211     }
212 
213     /**
214      * Gets the Default auto-commit value.
215      *
216      * @return The default auto-commit value.
217      * @since 2.6.0
218      */
219     public Boolean getDefaultAutoCommit() {
220         return defaultAutoCommit;
221     }
222 
223     /**
224      * Gets the default catalog.
225      *
226      * @return The default catalog.
227      * @since 2.6.0
228      */
229     public String getDefaultCatalog() {
230         return defaultCatalog;
231     }
232 
233     /**
234      * Gets the default query timeout in seconds.
235      *
236      * @return The default query timeout in seconds.
237      * @deprecated Use {@link #getDefaultQueryTimeoutDuration()}.
238      */
239     @Deprecated
240     public Integer getDefaultQueryTimeout() {
241         return getDefaultQueryTimeoutSeconds();
242     }
243 
244     /**
245      * Gets the default query timeout Duration.
246      *
247      * @return The default query timeout Duration.
248      * @since 2.10.0
249      */
250     public Duration getDefaultQueryTimeoutDuration() {
251         return defaultQueryTimeoutDuration;
252     }
253 
254     /**
255      * Gets the default query timeout in seconds.
256      *
257      * @return The default query timeout in seconds.
258      * @since 2.6.0
259      * @deprecated Use {@link #getDefaultQueryTimeoutDuration()}.
260      */
261     @Deprecated
262     public Integer getDefaultQueryTimeoutSeconds() {
263         return defaultQueryTimeoutDuration == null ? null : (int) defaultQueryTimeoutDuration.getSeconds();
264     }
265 
266     /**
267      * Gets the default read-only-value.
268      *
269      * @return The default read-only-value.
270      * @since 2.6.0
271      */
272     public Boolean getDefaultReadOnly() {
273         return defaultReadOnly;
274     }
275 
276     /**
277      * Gets the default schema.
278      *
279      * @return The default schema.
280      * @since 2.6.0
281      */
282     public String getDefaultSchema() {
283         return defaultSchema;
284     }
285 
286     /**
287      * Gets the default transaction isolation.
288      *
289      * @return The default transaction isolation.
290      * @since 2.6.0
291      */
292     public int getDefaultTransactionIsolation() {
293         return defaultTransactionIsolation;
294     }
295 
296     /**
297      * Gets the collection of SQL State codes that are not considered fatal disconnection codes.
298      * <p>
299      * This method returns the collection of SQL State codes that have been set to be ignored when
300      * determining if a {@link SQLException} signals a disconnection. These codes are excluded from
301      * being treated as fatal even if they match the typical disconnection criteria.
302      * </p>
303      *
304      * @return a {@link Collection} of SQL State codes that should be ignored for disconnection checks.
305      * @since 2.13.0
306      */
307     public Collection<String> getDisconnectionIgnoreSqlCodes() {
308         return disconnectionIgnoreSqlCodes;
309     }
310 
311     /**
312      * Gets SQL State codes considered to signal fatal conditions.
313      * <p>
314      * Overrides the defaults in {@link Utils#getDisconnectionSqlCodes()} (plus anything starting with
315      * {@link Utils#DISCONNECTION_SQL_CODE_PREFIX}). If this property is non-null and {@link #isFastFailValidation()} is
316      * {@code true}, whenever connections created by this factory generate exceptions with SQL State codes in this list,
317      * they will be marked as "fatally disconnected" and subsequent validations will fail fast (no attempt at isValid or
318      * validation query).
319      * </p>
320      * <p>
321      * If {@link #isFastFailValidation()} is {@code false} setting this property has no effect.
322      * </p>
323      *
324      * @return SQL State codes overriding defaults
325      * @since 2.1
326      */
327     public Collection<String> getDisconnectionSqlCodes() {
328         return disconnectionSqlCodes;
329     }
330 
331     /**
332      * Gets the Maximum connection duration.
333      *
334      * @return Maximum connection duration.
335      * @since 2.10.0
336      */
337     public Duration getMaxConnDuration() {
338         return maxConnDuration;
339     }
340 
341     /**
342      * Gets the Maximum connection lifetime in milliseconds.
343      *
344      * @return Maximum connection lifetime in milliseconds.
345      * @since 2.6.0
346      */
347     public long getMaxConnLifetimeMillis() {
348         return maxConnDuration.toMillis();
349     }
350 
351     /**
352      * Gets the maximum number of open prepared statements.
353      *
354      * @return The maximum number of open prepared statements.
355      */
356     protected int getMaxOpenPreparedStatements() {
357         return maxOpenPreparedStatements;
358     }
359 
360     /**
361      * Returns the {@link ObjectPool} in which {@link Connection}s are pooled.
362      *
363      * @return the connection pool
364      */
365     public synchronized ObjectPool<PoolableConnection> getPool() {
366         return pool;
367     }
368 
369     /**
370      * Tests whether to pool statements.
371      *
372      * @return Whether to pool statements.
373      * @since 2.6.0.
374      */
375     public boolean getPoolStatements() {
376         return poolStatements;
377     }
378 
379     /**
380      * Gets the validation query.
381      *
382      * @return Validation query.
383      * @since 2.6.0
384      */
385     public String getValidationQuery() {
386         return validationQuery;
387     }
388 
389     /**
390      * Gets the query timeout in seconds.
391      *
392      * @return Validation query timeout in seconds.
393      * @since 2.10.0
394      */
395     public Duration getValidationQueryTimeoutDuration() {
396         return validationQueryTimeoutDuration;
397     }
398 
399     /**
400      * Gets the query timeout in seconds.
401      *
402      * @return Validation query timeout in seconds.
403      * @since 2.6.0
404      * @deprecated Use {@link #getValidationQueryTimeoutDuration()}.
405      */
406     @Deprecated
407     public int getValidationQueryTimeoutSeconds() {
408         return (int) validationQueryTimeoutDuration.getSeconds();
409     }
410 
411     /**
412      * Initializes the given connection with the collection of SQL statements set in {@link #setConnectionInitSql(Collection)}.
413      *
414      * @param conn the connection to initialize.
415      * @throws SQLException if a database access error occurs or this method is called on a closed connection.
416      * @see #setConnectionInitSql(Collection)
417      */
418     protected void initializeConnection(final Connection conn) throws SQLException {
419         final Collection<String> sqls = connectionInitSqls;
420         if (conn.isClosed()) {
421             throw new SQLException("initializeConnection: connection closed");
422         }
423         if (!Utils.isEmpty(sqls)) {
424             try (Statement statement = conn.createStatement()) {
425                 for (final String sql : sqls) {
426                     statement.execute(Objects.requireNonNull(sql, "null connectionInitSqls element"));
427                 }
428             }
429         }
430     }
431 
432     /**
433      * Tests whether to set auto-commit on {@link #passivateObject(PooledObject)}.
434      *
435      * @return Whether to set auto-commit on {@link #passivateObject(PooledObject)}.
436      * @since 2.6.0
437      */
438     public boolean isAutoCommitOnReturn() {
439         return autoCommitOnReturn;
440     }
441 
442     /**
443      * Tests whether to set auto-commit on {@link #passivateObject(PooledObject)}.
444      *
445      * @return Whether to set auto-commit on {@link #passivateObject(PooledObject)}.
446      * @deprecated Use {@link #isAutoCommitOnReturn()}.
447      */
448     @Deprecated
449     public boolean isEnableAutoCommitOnReturn() {
450         return autoCommitOnReturn;
451     }
452 
453     /**
454      * True means that validation will fail immediately for connections that have previously thrown SQLExceptions with
455      * SQL State indicating fatal disconnection errors.
456      *
457      * @return true if connections created by this factory will fast fail validation.
458      * @see #setDisconnectionSqlCodes(Collection)
459      * @since 2.1
460      * @since 2.5.0 Defaults to true, previous versions defaulted to false.
461      */
462     public boolean isFastFailValidation() {
463         return fastFailValidation;
464     }
465 
466     /**
467      * Tests whether to rollback on return.
468      *
469      * @return Whether to rollback on return.
470      */
471     public boolean isRollbackOnReturn() {
472         return rollbackOnReturn;
473     }
474 
475     @Override
476     public PooledObject<PoolableConnection> makeObject() throws SQLException {
477         Connection conn = connectionFactory.createConnection();
478         if (conn == null) {
479             throw new IllegalStateException("Connection factory returned null from createConnection");
480         }
481         try {
482             initializeConnection(conn);
483         } catch (final SQLException e) {
484             // Make sure the connection is closed
485             Utils.closeQuietly((AutoCloseable) conn);
486             // Rethrow original exception so it is visible to caller
487             throw e;
488         }
489 
490         final long connIndex = connectionIndex.getAndIncrement();
491 
492         if (poolStatements) {
493             conn = new PoolingConnection(conn);
494             final GenericKeyedObjectPoolConfig<DelegatingPreparedStatement> config = new GenericKeyedObjectPoolConfig<>();
495             config.setMaxTotalPerKey(-1);
496             config.setBlockWhenExhausted(false);
497             config.setMaxWait(Duration.ZERO);
498             config.setMaxIdlePerKey(1);
499             config.setMaxTotal(maxOpenPreparedStatements);
500             if (dataSourceJmxObjectName != null) {
501                 final StringBuilder base = new StringBuilder(dataSourceJmxObjectName.toString());
502                 base.append(Constants.JMX_CONNECTION_BASE_EXT);
503                 base.append(connIndex);
504                 config.setJmxNameBase(base.toString());
505                 config.setJmxNamePrefix(Constants.JMX_STATEMENT_POOL_PREFIX);
506             } else {
507                 config.setJmxEnabled(false);
508             }
509             final PoolingConnection poolingConn = (PoolingConnection) conn;
510             final KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> stmtPool = new GenericKeyedObjectPool<>(poolingConn, config);
511             poolingConn.setStatementPool(stmtPool);
512             poolingConn.setClearStatementPoolOnReturn(clearStatementPoolOnReturn);
513             poolingConn.setCacheState(cacheState);
514         }
515 
516         // Register this connection with JMX
517         final ObjectName connJmxName;
518         if (dataSourceJmxObjectName == null) {
519             connJmxName = null;
520         } else {
521             final String name = dataSourceJmxObjectName.toString() + Constants.JMX_CONNECTION_BASE_EXT + connIndex;
522             try {
523                 connJmxName = new ObjectName(name);
524             } catch (final MalformedObjectNameException e) {
525                 Utils.closeQuietly((AutoCloseable) conn);
526                 throw new SQLException(name, e);
527             }
528         }
529 
530         final PoolableConnection pc = new PoolableConnection(conn, pool, connJmxName,
531                 disconnectionSqlCodes, disconnectionIgnoreSqlCodes, fastFailValidation);
532         pc.setCacheState(cacheState);
533 
534         return new DefaultPooledObject<>(pc);
535     }
536 
537     @Override
538     public void passivateObject(final PooledObject<PoolableConnection> p) throws SQLException {
539 
540         validateLifetime(p);
541 
542         final PoolableConnection conn = p.getObject();
543         Boolean connAutoCommit = null;
544         if (rollbackOnReturn) {
545             connAutoCommit = conn.getAutoCommit();
546             if (!connAutoCommit && !conn.isReadOnly()) {
547                 conn.rollback();
548             }
549         }
550 
551         conn.clearWarnings();
552 
553         // DBCP-97 / DBCP-399 / DBCP-351 Idle connections in the pool should
554         // have autoCommit enabled
555         if (autoCommitOnReturn) {
556             if (connAutoCommit == null) {
557                 connAutoCommit = conn.getAutoCommit();
558             }
559             if (!connAutoCommit) {
560                 conn.setAutoCommit(true);
561             }
562         }
563 
564         conn.passivate();
565     }
566 
567     /**
568      * Sets whether to set auto-commit on {@link #passivateObject(PooledObject)}.
569      *
570      * @param autoCommitOnReturn whether to set auto-commit.
571      */
572     public void setAutoCommitOnReturn(final boolean autoCommitOnReturn) {
573         this.autoCommitOnReturn = autoCommitOnReturn;
574     }
575 
576     /**
577      * Sets the cache state to propagate in {@link #makeObject()}.
578      *
579      * @param cacheState the cache state to propagate.
580      */
581     public void setCacheState(final boolean cacheState) {
582         this.cacheState = cacheState;
583     }
584 
585     /**
586      * Sets whether the pool of statements (which was enabled with {@link #setPoolStatements(boolean)}) should
587      * be cleared when the connection is returned to its pool. Default is false.
588      *
589      * @param clearStatementPoolOnReturn clear or not
590      * @since 2.8.0
591      */
592     public void setClearStatementPoolOnReturn(final boolean clearStatementPoolOnReturn) {
593         this.clearStatementPoolOnReturn = clearStatementPoolOnReturn;
594     }
595 
596     /**
597      * Sets the SQL statements I use to initialize newly created {@link Connection}s. Using {@code null} turns off
598      * connection initialization.
599      *
600      * @param connectionInitSqls
601      *            SQL statement to initialize {@link Connection}s.
602      */
603     public void setConnectionInitSql(final Collection<String> connectionInitSqls) {
604         this.connectionInitSqls = connectionInitSqls;
605     }
606     /**
607      * Sets the default "auto commit" setting for borrowed {@link Connection}s
608      *
609      * @param defaultAutoCommit
610      *            the default "auto commit" setting for borrowed {@link Connection}s
611      */
612     public void setDefaultAutoCommit(final Boolean defaultAutoCommit) {
613         this.defaultAutoCommit = defaultAutoCommit;
614     }
615 
616     /**
617      * Sets the default "catalog" setting for borrowed {@link Connection}s
618      *
619      * @param defaultCatalog
620      *            the default "catalog" setting for borrowed {@link Connection}s
621      */
622     public void setDefaultCatalog(final String defaultCatalog) {
623         this.defaultCatalog = defaultCatalog;
624     }
625 
626     /**
627      * Sets the query timeout Duration.
628      *
629      * @param defaultQueryTimeoutDuration the query timeout Duration.
630      * @since 2.10.0
631      */
632     public void setDefaultQueryTimeout(final Duration defaultQueryTimeoutDuration) {
633         this.defaultQueryTimeoutDuration = defaultQueryTimeoutDuration;
634     }
635 
636     /**
637      * Sets the query timeout in seconds.
638      *
639      * @param defaultQueryTimeoutSeconds the query timeout in seconds.
640      * @deprecated Use {@link #setDefaultQueryTimeout(Duration)}.
641      */
642     @Deprecated
643     public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) {
644         this.defaultQueryTimeoutDuration = defaultQueryTimeoutSeconds == null ? null : Duration.ofSeconds(defaultQueryTimeoutSeconds);
645     }
646 
647     /**
648      * Sets the default "read only" setting for borrowed {@link Connection}s
649      *
650      * @param defaultReadOnly
651      *            the default "read only" setting for borrowed {@link Connection}s
652      */
653     public void setDefaultReadOnly(final Boolean defaultReadOnly) {
654         this.defaultReadOnly = defaultReadOnly;
655     }
656 
657     /**
658      * Sets the default "schema" setting for borrowed {@link Connection}s
659      *
660      * @param defaultSchema
661      *            the default "schema" setting for borrowed {@link Connection}s
662      * @since 2.5.0
663      */
664     public void setDefaultSchema(final String defaultSchema) {
665         this.defaultSchema = defaultSchema;
666     }
667 
668     /**
669      * Sets the default "Transaction Isolation" setting for borrowed {@link Connection}s
670      *
671      * @param defaultTransactionIsolation
672      *            the default "Transaction Isolation" setting for returned {@link Connection}s
673      */
674     public void setDefaultTransactionIsolation(final int defaultTransactionIsolation) {
675         this.defaultTransactionIsolation = defaultTransactionIsolation;
676     }
677 
678     /**
679      * Sets the disconnection SQL codes to ignore.
680      *
681      * @param disconnectionIgnoreSqlCodes
682      *            The collection of SQL State codes to be ignored.
683      * @see #getDisconnectionIgnoreSqlCodes()
684      * @throws IllegalArgumentException if any SQL state codes overlap with those in {@link #disconnectionSqlCodes}.
685      * @since 2.13.0
686      */
687     public void setDisconnectionIgnoreSqlCodes(final Collection<String> disconnectionIgnoreSqlCodes) {
688         Utils.checkSqlCodes(disconnectionIgnoreSqlCodes, this.disconnectionSqlCodes);
689         this.disconnectionIgnoreSqlCodes = disconnectionIgnoreSqlCodes;
690     }
691 
692     /**
693      * Sets the disconnection SQL codes.
694      *
695      * @param disconnectionSqlCodes
696      *            The disconnection SQL codes.
697      * @see #getDisconnectionSqlCodes()
698      * @throws IllegalArgumentException if any SQL state codes overlap with those in {@link #disconnectionIgnoreSqlCodes}.
699      * @since 2.1
700      */
701     public void setDisconnectionSqlCodes(final Collection<String> disconnectionSqlCodes) {
702         Utils.checkSqlCodes(disconnectionSqlCodes, this.disconnectionIgnoreSqlCodes);
703         this.disconnectionSqlCodes = disconnectionSqlCodes;
704     }
705 
706     /**
707      * Sets whether to set auto-commit on {@link #passivateObject(PooledObject)}.
708      *
709      * @param autoCommitOnReturn whether to set auto-commit.
710      */
711     @Deprecated
712     public void setEnableAutoCommitOnReturn(final boolean autoCommitOnReturn) {
713         this.autoCommitOnReturn = autoCommitOnReturn;
714     }
715 
716     /**
717      * Sets whether connections created by this factory will fast fail validation.
718      *
719      * @param fastFailValidation true means connections created by this factory will fast fail validation
720      * @see #isFastFailValidation()
721      * @since 2.1
722      */
723     public void setFastFailValidation(final boolean fastFailValidation) {
724         this.fastFailValidation = fastFailValidation;
725     }
726 
727     /**
728      * Sets the maximum lifetime in milliseconds of a connection after which the connection will always fail activation,
729      * passivation and validation. A value of zero or less indicates an infinite lifetime. The default value is -1.
730      *
731      * @param maxConnDuration
732      *            The maximum lifetime in milliseconds.
733      * @since 2.10.0
734      */
735     public void setMaxConn(final Duration maxConnDuration) {
736         this.maxConnDuration = maxConnDuration;
737     }
738 
739     /**
740      * Sets the maximum lifetime in milliseconds of a connection after which the connection will always fail activation,
741      * passivation and validation. A value of zero or less indicates an infinite lifetime. The default value is -1.
742      *
743      * @param maxConnLifetimeMillis
744      *            The maximum lifetime in milliseconds.
745      * @deprecated Use {@link #setMaxConn(Duration)}.
746      */
747     @Deprecated
748     public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
749         this.maxConnDuration = Duration.ofMillis(maxConnLifetimeMillis);
750     }
751 
752     /**
753      * Sets the maximum number of open prepared statements.
754      *
755      * @param maxOpenPreparedStatements
756      *            The maximum number of open prepared statements.
757      */
758     public void setMaxOpenPreparedStatements(final int maxOpenPreparedStatements) {
759         this.maxOpenPreparedStatements = maxOpenPreparedStatements;
760     }
761 
762     /**
763      * Deprecated due to typo in method name.
764      *
765      * @param maxOpenPreparedStatements
766      *            The maximum number of open prepared statements.
767      * @deprecated Use {@link #setMaxOpenPreparedStatements(int)}.
768      */
769     @Deprecated // Due to typo in method name.
770     public void setMaxOpenPrepatedStatements(final int maxOpenPreparedStatements) {
771         setMaxOpenPreparedStatements(maxOpenPreparedStatements);
772     }
773 
774     /**
775      * Sets the {@link ObjectPool} in which to pool {@link Connection}s.
776      *
777      * @param pool
778      *            the {@link ObjectPool} in which to pool those {@link Connection}s
779      */
780     public synchronized void setPool(final ObjectPool<PoolableConnection> pool) {
781         if (null != this.pool && pool != this.pool) {
782             Utils.closeQuietly(this.pool);
783         }
784         this.pool = pool;
785     }
786 
787     /**
788      * Sets whether to pool statements.
789      *
790      * @param poolStatements whether to pool statements.
791      */
792     public void setPoolStatements(final boolean poolStatements) {
793         this.poolStatements = poolStatements;
794     }
795 
796     /**
797      * Sets whether to rollback on return.
798      *
799      * @param rollbackOnReturn whether to rollback on return.
800      */
801     public void setRollbackOnReturn(final boolean rollbackOnReturn) {
802         this.rollbackOnReturn = rollbackOnReturn;
803     }
804 
805     /**
806      * Sets the query I use to {@link #validateObject validate} {@link Connection}s. Should return at least one row. If
807      * not specified, {@link Connection#isValid(int)} will be used to validate connections.
808      *
809      * @param validationQuery
810      *            a query to use to {@link #validateObject validate} {@link Connection}s.
811      */
812     public void setValidationQuery(final String validationQuery) {
813         this.validationQuery = validationQuery;
814     }
815 
816     /**
817      * Sets the validation query timeout, the amount of time, that connection validation will wait for a response from the
818      * database when executing a validation query. Use a value less than or equal to 0 for no timeout.
819      *
820      * @param validationQueryTimeoutDuration new validation query timeout duration.
821      * @since 2.10.0
822      */
823     public void setValidationQueryTimeout(final Duration validationQueryTimeoutDuration) {
824         this.validationQueryTimeoutDuration = validationQueryTimeoutDuration;
825     }
826 
827     /**
828      * Sets the validation query timeout, the amount of time, in seconds, that connection validation will wait for a
829      * response from the database when executing a validation query. Use a value less than or equal to 0 for no timeout.
830      *
831      * @param validationQueryTimeoutSeconds
832      *            new validation query timeout value in seconds
833      * @deprecated {@link #setValidationQueryTimeout(Duration)}.
834      */
835     @Deprecated
836     public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) {
837         this.validationQueryTimeoutDuration = Duration.ofSeconds(validationQueryTimeoutSeconds);
838     }
839 
840     /**
841      * Validates the given connection if it is open.
842      *
843      * @param conn the connection to validate.
844      * @throws SQLException if the connection is closed or validate fails.
845      */
846     public void validateConnection(final PoolableConnection conn) throws SQLException {
847         if (conn.isClosed()) {
848             throw new SQLException("validateConnection: connection closed");
849         }
850         conn.validate(validationQuery, validationQueryTimeoutDuration);
851     }
852 
853     private void validateLifetime(final PooledObject<PoolableConnection> p) throws LifetimeExceededException {
854         Utils.validateLifetime(p, maxConnDuration);
855     }
856 
857     @Override
858     public boolean validateObject(final PooledObject<PoolableConnection> p) {
859         try {
860             validateLifetime(p);
861             validateConnection(p.getObject());
862             return true;
863         } catch (final Exception e) {
864             if (log.isDebugEnabled()) {
865                 log.debug(Utils.getMessage("poolableConnectionFactory.validateObject.fail"), e);
866             }
867             return false;
868         }
869     }
870 }