1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.dbcp2.datasources;
19
20 import java.sql.Connection;
21 import java.sql.ResultSet;
22 import java.sql.SQLException;
23 import java.sql.Statement;
24 import java.time.Duration;
25 import java.util.Collections;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.concurrent.ConcurrentHashMap;
29
30 import javax.sql.ConnectionPoolDataSource;
31 import javax.sql.PooledConnection;
32
33 import org.apache.commons.dbcp2.Utils;
34 import org.apache.commons.pool2.PooledObject;
35
36
37
38
39 class AbstractConnectionFactory {
40
41 protected final ConnectionPoolDataSource cpds;
42 protected Duration maxConnDuration = Duration.ofMillis(-1);
43 protected final boolean rollbackAfterValidation;
44
45
46
47
48 protected final Map<PooledConnection, PooledConnectionAndInfo> pcMap = new ConcurrentHashMap<>();
49
50
51
52
53 protected final Set<PooledConnection> validatingSet = Collections.newSetFromMap(new ConcurrentHashMap<>());
54 protected final String validationQuery;
55 protected final Duration validationQueryTimeoutDuration;
56
57 public AbstractConnectionFactory(final ConnectionPoolDataSource cpds, final String validationQuery, final Duration validationQueryTimeoutDuration, final boolean rollbackAfterValidation) {
58 this.cpds = cpds;
59 this.validationQuery = validationQuery;
60 this.validationQueryTimeoutDuration = validationQueryTimeoutDuration;
61 this.rollbackAfterValidation = rollbackAfterValidation;
62 }
63
64
65
66
67
68
69
70
71
72 void setMaxConn(final Duration duration) {
73 this.maxConnDuration = duration;
74 }
75
76
77
78
79
80
81
82
83 private int toSeconds(final Duration duration) {
84 if (duration.isNegative() || duration.isZero()) {
85 return 0;
86 }
87 final long seconds = validationQueryTimeoutDuration.getSeconds();
88 return seconds != 0 ? Math.toIntExact(seconds) : 1;
89 }
90
91 protected void validateLifetime(final PooledObject<PooledConnectionAndInfo> pooledObject) throws SQLException {
92 Utils.validateLifetime(pooledObject, maxConnDuration);
93 }
94
95 public boolean validateObject(final PooledObject<PooledConnectionAndInfo> pooledObject) {
96 try {
97 validateLifetime(pooledObject);
98 } catch (final Exception e) {
99 return false;
100 }
101 boolean valid = false;
102 final PooledConnection pooledConn = pooledObject.getObject().getPooledConnection();
103 Connection conn = null;
104
105
106
107
108 validatingSet.add(pooledConn);
109 try {
110 final int timeoutSeconds = toSeconds(validationQueryTimeoutDuration);
111 if (validationQuery == null) {
112 try {
113 conn = pooledConn.getConnection();
114 valid = conn.isValid(timeoutSeconds);
115 } catch (final SQLException e) {
116 valid = false;
117 }
118 } else {
119 Statement stmt = null;
120 ResultSet rset = null;
121 try {
122 conn = pooledConn.getConnection();
123 stmt = conn.createStatement();
124 if (timeoutSeconds > 0) {
125 stmt.setQueryTimeout(timeoutSeconds);
126 }
127 rset = stmt.executeQuery(validationQuery);
128 valid = rset.next();
129 if (rollbackAfterValidation) {
130 conn.rollback();
131 }
132 } catch (final Exception e) {
133 valid = false;
134 } finally {
135 Utils.closeQuietly((AutoCloseable) rset);
136 Utils.closeQuietly((AutoCloseable) stmt);
137 }
138 }
139 } finally {
140 Utils.closeQuietly((AutoCloseable) conn);
141 validatingSet.remove(pooledConn);
142 }
143 return valid;
144 }
145
146 }