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");
103 this.pool = pool;
104
105 if (this.pool instanceof GenericObjectPool<?>) {
106 final PoolableConnectionFactory pcf = (PoolableConnectionFactory) ((GenericObjectPool<?>) this.pool).getFactory();
107 Objects.requireNonNull(pcf, "this.pool.getFactory()");
108 if (pcf.getPool() != this.pool) {
109 log.warn(Utils.getMessage("poolingDataSource.factoryConfig"));
110 @SuppressWarnings("unchecked")
111 final ObjectPool<PoolableConnection> p = (ObjectPool<PoolableConnection>) this.pool;
112 pcf.setPool(p);
113 }
114 }
115 }
116
117
118
119
120
121
122 @Override
123 public void close() throws SQLException {
124 try {
125 pool.close();
126 } catch (final Exception e) {
127 throw new SQLException(Utils.getMessage("pool.close.fail"), e);
128 }
129 }
130
131
132
133
134
135 @Override
136 public Connection getConnection() throws SQLException {
137 try {
138 final C conn = pool.borrowObject();
139 if (conn == null) {
140 return null;
141 }
142 return new PoolGuardConnectionWrapper<>(conn);
143 } catch (final NoSuchElementException e) {
144 throw new SQLException("Cannot get a connection, pool error " + e.getMessage(), e);
145 } catch (final SQLException | RuntimeException e) {
146 throw e;
147 } catch (final InterruptedException e) {
148
149 Thread.currentThread().interrupt();
150 throw new SQLException("Cannot get a connection, general error", e);
151 } catch (final Exception e) {
152 throw new SQLException("Cannot get a connection, general error", e);
153 }
154 }
155
156
157
158
159
160
161
162 @Override
163 public Connection getConnection(final String userName, final String password) throws SQLException {
164 throw new UnsupportedOperationException();
165 }
166
167
168
169
170
171
172
173
174 @Override
175 public int getLoginTimeout() {
176 throw new UnsupportedOperationException("Login timeout is not supported.");
177 }
178
179
180
181
182
183
184
185 @Override
186 public PrintWriter getLogWriter() {
187 return logWriter;
188 }
189
190 @Override
191 public Logger getParentLogger() throws SQLFeatureNotSupportedException {
192 throw new SQLFeatureNotSupportedException();
193 }
194
195
196
197
198
199
200 protected ObjectPool<C> getPool() {
201 return pool;
202 }
203
204
205
206
207
208
209 public boolean isAccessToUnderlyingConnectionAllowed() {
210 return this.accessToUnderlyingConnectionAllowed;
211 }
212
213 @Override
214 public boolean isWrapperFor(final Class<?> iface) throws SQLException {
215 return iface != null && iface.isInstance(this);
216 }
217
218
219
220
221
222
223
224
225 public void setAccessToUnderlyingConnectionAllowed(final boolean allow) {
226 this.accessToUnderlyingConnectionAllowed = allow;
227 }
228
229
230
231
232
233
234
235 @Override
236 public void setLoginTimeout(final int seconds) {
237 throw new UnsupportedOperationException("Login timeout is not supported.");
238 }
239
240
241
242
243
244
245 @Override
246 public void setLogWriter(final PrintWriter out) {
247 logWriter = out;
248 }
249
250 @Override
251 public <T> T unwrap(final Class<T> iface) throws SQLException {
252 if (isWrapperFor(iface)) {
253 return iface.cast(this);
254 }
255 throw new SQLException(this + " is not a wrapper for " + iface);
256 }
257 }