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