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 public static final String URL_PREFIX = "jdbc:apache:commons:dbcp:";
92
93 protected static final int URL_PREFIX_LEN = URL_PREFIX.length();
94
95
96 protected static final int MAJOR_VERSION = 1;
97
98 protected static final int MINOR_VERSION = 0;
99
100
101 private final boolean accessToUnderlyingConnectionAllowed;
102
103
104
105
106 public PoolingDriver() {
107 this(true);
108 }
109
110
111
112
113
114
115
116 protected PoolingDriver(final boolean accessToUnderlyingConnectionAllowed) {
117 this.accessToUnderlyingConnectionAllowed = accessToUnderlyingConnectionAllowed;
118 }
119
120 @Override
121 public boolean acceptsURL(final String url) throws SQLException {
122 return url != null && url.startsWith(URL_PREFIX);
123 }
124
125
126
127
128
129
130
131
132
133 public synchronized void closePool(final String name) throws SQLException {
134 @SuppressWarnings("resource")
135 final ObjectPool<? extends Connection> pool = pools.get(name);
136 if (pool != null) {
137 pools.remove(name);
138 try {
139 pool.close();
140 } catch (final Exception e) {
141 throw new SQLException("Error closing pool " + name, e);
142 }
143 }
144 }
145
146 @Override
147 public Connection connect(final String url, final Properties info) throws SQLException {
148 if (acceptsURL(url)) {
149 final ObjectPool<? extends Connection> pool = getConnectionPool(url.substring(URL_PREFIX_LEN));
150
151 try {
152 final Connection conn = pool.borrowObject();
153 if (conn == null) {
154 return null;
155 }
156 return new PoolGuardConnectionWrapper(pool, conn);
157 } catch (final NoSuchElementException e) {
158 throw new SQLException("Cannot get a connection, pool error: " + e.getMessage(), e);
159 } catch (final SQLException | RuntimeException e) {
160 throw e;
161 } catch (final Exception e) {
162 throw new SQLException("Cannot get a connection, general error: " + e.getMessage(), e);
163 }
164 }
165 return null;
166 }
167
168
169
170
171
172
173
174
175
176
177 public synchronized ObjectPool<? extends Connection> getConnectionPool(final String name) throws SQLException {
178 final ObjectPool<? extends Connection> pool = pools.get(name);
179 if (null == pool) {
180 throw new SQLException("Pool not registered: " + name);
181 }
182 return pool;
183 }
184
185 @Override
186 public int getMajorVersion() {
187 return MAJOR_VERSION;
188 }
189
190 @Override
191 public int getMinorVersion() {
192 return MINOR_VERSION;
193 }
194
195 @Override
196 public Logger getParentLogger() throws SQLFeatureNotSupportedException {
197 throw new SQLFeatureNotSupportedException();
198 }
199
200
201
202
203
204
205 public synchronized String[] getPoolNames() {
206 return pools.keySet().toArray(Utils.EMPTY_STRING_ARRAY);
207 }
208
209 @Override
210 public DriverPropertyInfo[] getPropertyInfo(final String url, final Properties info) {
211 return EMPTY_DRIVER_PROPERTY_INFO_ARRAY;
212 }
213
214
215
216
217
218
219
220
221
222 public void invalidateConnection(final Connection conn) throws SQLException {
223 if (!(conn instanceof PoolGuardConnectionWrapper)) {
224 throw new SQLException("Invalid connection class");
225 }
226 final PoolGuardConnectionWrapper pgconn = (PoolGuardConnectionWrapper) conn;
227 @SuppressWarnings("unchecked")
228 final ObjectPool<Connection> pool = (ObjectPool<Connection>) pgconn.pool;
229 try {
230 pool.invalidateObject(pgconn.getDelegateInternal());
231 } catch (final Exception ignored) {
232
233 }
234 }
235
236
237
238
239
240
241 protected boolean isAccessToUnderlyingConnectionAllowed() {
242 return accessToUnderlyingConnectionAllowed;
243 }
244
245 @Override
246 public boolean jdbcCompliant() {
247 return true;
248 }
249
250
251
252
253
254
255
256
257
258 public synchronized void registerPool(final String name, final ObjectPool<? extends Connection> pool) {
259 pools.put(name, pool);
260 }
261 }