1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.dbcp2;
18
19 import java.io.PrintWriter;
20 import java.sql.Connection;
21 import java.sql.SQLException;
22 import java.sql.SQLFeatureNotSupportedException;
23 import java.util.NoSuchElementException;
24 import java.util.Objects;
25 import java.util.logging.Logger;
26
27 import javax.sql.DataSource;
28
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.apache.commons.pool2.ObjectPool;
32 import org.apache.commons.pool2.impl.GenericObjectPool;
33
34
35
36
37
38
39
40
41
42 public class PoolingDataSource<C extends Connection> implements DataSource, AutoCloseable {
43
44
45
46
47
48
49 private final class PoolGuardConnectionWrapper<D extends Connection> extends DelegatingConnection<D> {
50
51 PoolGuardConnectionWrapper(final D delegate) {
52 super(delegate);
53 }
54
55 @Override
56 public void close() throws SQLException {
57 if (getDelegateInternal() != null) {
58 super.close();
59 super.setDelegate(null);
60 }
61 }
62
63
64
65
66 @Override
67 public D getDelegate() {
68 return isAccessToUnderlyingConnectionAllowed() ? super.getDelegate() : null;
69 }
70
71
72
73
74 @Override
75 public Connection getInnermostDelegate() {
76 return isAccessToUnderlyingConnectionAllowed() ? super.getInnermostDelegate() : null;
77 }
78
79 @Override
80 public boolean isClosed() throws SQLException {
81 return getDelegateInternal() == null || super.isClosed();
82 }
83 }
84
85 private static final Log log = LogFactory.getLog(PoolingDataSource.class);
86
87
88 private boolean accessToUnderlyingConnectionAllowed;
89
90
91 private PrintWriter logWriter;
92
93 private final ObjectPool<C> pool;
94
95
96
97
98
99
100
101 public PoolingDataSource(final ObjectPool<C> pool) {
102 Objects.requireNonNull(pool, "Pool must not be null.");
103 this.pool = pool;
104
105 if (this.pool instanceof GenericObjectPool<?>) {
106 final PoolableConnectionFactory pcf = (PoolableConnectionFactory) ((GenericObjectPool<?>) this.pool)
107 .getFactory();
108 Objects.requireNonNull(pcf, "PoolableConnectionFactory must not be null.");
109 if (pcf.getPool() != this.pool) {
110 log.warn(Utils.getMessage("poolingDataSource.factoryConfig"));
111 @SuppressWarnings("unchecked")
112 final ObjectPool<PoolableConnection> p = (ObjectPool<PoolableConnection>) this.pool;
113 pcf.setPool(p);
114 }
115 }
116 }
117
118
119
120
121
122
123 @Override
124 public void close() throws SQLException {
125 try {
126 pool.close();
127 } catch (final Exception e) {
128 throw new SQLException(Utils.getMessage("pool.close.fail"), e);
129 }
130 }
131
132
133
134
135
136 @Override
137 public Connection getConnection() throws SQLException {
138 try {
139 final C conn = pool.borrowObject();
140 if (conn == null) {
141 return null;
142 }
143 return new PoolGuardConnectionWrapper<>(conn);
144 } catch (final NoSuchElementException e) {
145 throw new SQLException("Cannot get a connection, pool error " + e.getMessage(), e);
146 } catch (final SQLException | RuntimeException e) {
147 throw e;
148 } catch (final InterruptedException e) {
149
150 Thread.currentThread().interrupt();
151 throw new SQLException("Cannot get a connection, general error", e);
152 } catch (final Exception e) {
153 throw new SQLException("Cannot get a connection, general error", e);
154 }
155 }
156
157
158
159
160
161
162
163 @Override
164 public Connection getConnection(final String userName, final String password) throws SQLException {
165 throw new UnsupportedOperationException();
166 }
167
168
169
170
171
172
173
174
175
176 @Override
177 public int getLoginTimeout() {
178 throw new UnsupportedOperationException("Login timeout is not supported.");
179 }
180
181
182
183
184
185
186
187 @Override
188 public PrintWriter getLogWriter() {
189 return logWriter;
190 }
191
192 @Override
193 public Logger getParentLogger() throws SQLFeatureNotSupportedException {
194 throw new SQLFeatureNotSupportedException();
195 }
196
197 protected ObjectPool<C> getPool() {
198 return pool;
199 }
200
201
202
203
204
205
206 public boolean isAccessToUnderlyingConnectionAllowed() {
207 return this.accessToUnderlyingConnectionAllowed;
208 }
209
210 @Override
211 public boolean isWrapperFor(final Class<?> iface) throws SQLException {
212 return iface != null && iface.isInstance(this);
213 }
214
215
216
217
218
219
220
221
222 public void setAccessToUnderlyingConnectionAllowed(final boolean allow) {
223 this.accessToUnderlyingConnectionAllowed = allow;
224 }
225
226
227
228
229
230
231
232 @Override
233 public void setLoginTimeout(final int seconds) {
234 throw new UnsupportedOperationException("Login timeout is not supported.");
235 }
236
237
238
239
240
241
242 @Override
243 public void setLogWriter(final PrintWriter out) {
244 logWriter = out;
245 }
246
247 @Override
248 public <T> T unwrap(final Class<T> iface) throws SQLException {
249 if (isWrapperFor(iface)) {
250 return iface.cast(this);
251 }
252 throw new SQLException(this + " is not a wrapper for " + iface);
253 }
254 }