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.sql.Connection;
20 import java.sql.Driver;
21 import java.sql.DriverManager;
22 import java.sql.DriverPropertyInfo;
23 import java.sql.SQLException;
24 import java.sql.SQLFeatureNotSupportedException;
25 import java.util.HashMap;
26 import java.util.NoSuchElementException;
27 import java.util.Properties;
28 import java.util.logging.Logger;
29
30 import org.apache.commons.pool2.ObjectPool;
31
32
33
34
35
36
37 public class PoolingDriver implements Driver {
38
39
40
41
42
43
44 private final class PoolGuardConnectionWrapper extends DelegatingConnection<Connection> {
45
46 private final ObjectPool<? extends Connection> pool;
47
48 PoolGuardConnectionWrapper(final ObjectPool<? extends Connection> pool, final Connection delegate) {
49 super(delegate);
50 this.pool = pool;
51 }
52
53
54
55
56 @Override
57 public Connection getDelegate() {
58 if (isAccessToUnderlyingConnectionAllowed()) {
59 return super.getDelegate();
60 }
61 return null;
62 }
63
64
65
66
67 @Override
68 public Connection getInnermostDelegate() {
69 if (isAccessToUnderlyingConnectionAllowed()) {
70 return super.getInnermostDelegate();
71 }
72 return null;
73 }
74 }
75
76 private static final DriverPropertyInfo[] EMPTY_DRIVER_PROPERTY_INFO_ARRAY = {};
77
78
79 static {
80 try {
81 DriverManager.registerDriver(new PoolingDriver());
82 } catch (final Exception ignored) {
83
84 }
85 }
86
87
88 protected static final HashMap<String, ObjectPool<? extends Connection>> pools = new HashMap<>();
89
90
91
92
93 public static final String URL_PREFIX = "jdbc:apache:commons:dbcp:";
94
95
96
97
98 protected static final int URL_PREFIX_LEN = URL_PREFIX.length();
99
100
101
102
103 protected static final int MAJOR_VERSION = 1;
104
105
106
107
108 protected static final int MINOR_VERSION = 0;
109
110
111 private final boolean accessToUnderlyingConnectionAllowed;
112
113
114
115
116 public PoolingDriver() {
117 this(true);
118 }
119
120
121
122
123
124
125
126 protected PoolingDriver(final boolean accessToUnderlyingConnectionAllowed) {
127 this.accessToUnderlyingConnectionAllowed = accessToUnderlyingConnectionAllowed;
128 }
129
130 @Override
131 public boolean acceptsURL(final String url) throws SQLException {
132 return url != null && url.startsWith(URL_PREFIX);
133 }
134
135
136
137
138
139
140
141
142
143 public synchronized void closePool(final String name) throws SQLException {
144 @SuppressWarnings("resource")
145 final ObjectPool<? extends Connection> pool = pools.get(name);
146 if (pool != null) {
147 pools.remove(name);
148 try {
149 pool.close();
150 } catch (final Exception e) {
151 throw new SQLException("Error closing pool " + name, e);
152 }
153 }
154 }
155
156 @Override
157 public Connection connect(final String url, final Properties info) throws SQLException {
158 if (acceptsURL(url)) {
159 final ObjectPool<? extends Connection> pool = getConnectionPool(url.substring(URL_PREFIX_LEN));
160 try {
161 final Connection conn = pool.borrowObject();
162 if (conn == null) {
163 return null;
164 }
165 return new PoolGuardConnectionWrapper(pool, conn);
166 } catch (final NoSuchElementException e) {
167 throw new SQLException("Cannot get a connection, pool error: " + e.getMessage(), e);
168 } catch (final SQLException | RuntimeException e) {
169 throw e;
170 } catch (final Exception e) {
171 throw new SQLException("Cannot get a connection, general error: " + e.getMessage(), e);
172 }
173 }
174 return null;
175 }
176
177
178
179
180
181
182
183
184
185
186 public synchronized ObjectPool<? extends Connection> getConnectionPool(final String name) throws SQLException {
187 final ObjectPool<? extends Connection> pool = pools.get(name);
188 if (null == pool) {
189 throw new SQLException("Pool not registered: " + name);
190 }
191 return pool;
192 }
193
194 @Override
195 public int getMajorVersion() {
196 return MAJOR_VERSION;
197 }
198
199 @Override
200 public int getMinorVersion() {
201 return MINOR_VERSION;
202 }
203
204 @Override
205 public Logger getParentLogger() throws SQLFeatureNotSupportedException {
206 throw new SQLFeatureNotSupportedException();
207 }
208
209
210
211
212
213
214 public synchronized String[] getPoolNames() {
215 return pools.keySet().toArray(Utils.EMPTY_STRING_ARRAY);
216 }
217
218 @Override
219 public DriverPropertyInfo[] getPropertyInfo(final String url, final Properties info) {
220 return EMPTY_DRIVER_PROPERTY_INFO_ARRAY;
221 }
222
223
224
225
226
227
228
229
230
231 public void invalidateConnection(final Connection conn) throws SQLException {
232 if (!(conn instanceof PoolGuardConnectionWrapper)) {
233 throw new SQLException("Invalid connection class");
234 }
235 final PoolGuardConnectionWrapper pgconn = (PoolGuardConnectionWrapper) conn;
236 @SuppressWarnings("unchecked")
237 final ObjectPool<Connection> pool = (ObjectPool<Connection>) pgconn.pool;
238 try {
239 pool.invalidateObject(pgconn.getDelegateInternal());
240 } catch (final Exception ignored) {
241
242 }
243 }
244
245
246
247
248
249
250 protected boolean isAccessToUnderlyingConnectionAllowed() {
251 return accessToUnderlyingConnectionAllowed;
252 }
253
254 @Override
255 public boolean jdbcCompliant() {
256 return true;
257 }
258
259
260
261
262
263
264
265
266
267 public synchronized void registerPool(final String name, final ObjectPool<? extends Connection> pool) {
268 pools.put(name, pool);
269 }
270 }