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.CallableStatement;
20 import java.sql.Connection;
21 import java.sql.PreparedStatement;
22 import java.sql.SQLException;
23 import java.sql.Statement;
24 import java.util.NoSuchElementException;
25 import java.util.Objects;
26
27 import org.apache.commons.pool2.KeyedObjectPool;
28 import org.apache.commons.pool2.KeyedPooledObjectFactory;
29 import org.apache.commons.pool2.PooledObject;
30 import org.apache.commons.pool2.impl.DefaultPooledObject;
31 import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
32
33
34
35
36
37
38
39
40
41
42
43
44
45 public class PoolingConnection extends DelegatingConnection<Connection>
46 implements KeyedPooledObjectFactory<PStmtKey, DelegatingPreparedStatement> {
47
48
49
50
51
52
53
54
55
56
57
58
59 public enum StatementType {
60
61
62
63
64
65
66 CALLABLE_STATEMENT,
67
68
69
70
71
72
73 PREPARED_STATEMENT
74 }
75
76
77 private KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> pStmtPool;
78
79 private boolean clearStatementPoolOnReturn;
80
81
82
83
84
85
86
87 public PoolingConnection(final Connection connection) {
88 super(connection);
89 }
90
91
92
93
94
95
96
97
98
99 @Override
100 public void activateObject(final PStmtKey key, final PooledObject<DelegatingPreparedStatement> pooledObject)
101 throws SQLException {
102 pooledObject.getObject().activate();
103 }
104
105
106
107
108
109 @Override
110 public synchronized void close() throws SQLException {
111 try {
112 if (null != pStmtPool) {
113 final KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> oldPool = pStmtPool;
114 pStmtPool = null;
115 try {
116 oldPool.close();
117 } catch (final RuntimeException e) {
118 throw e;
119 } catch (final Exception e) {
120 throw new SQLException("Cannot close connection", e);
121 }
122 }
123 } finally {
124 try {
125 @SuppressWarnings("resource")
126 final Connection delegateInternal = getDelegateInternal();
127 if (delegateInternal != null) {
128 delegateInternal.close();
129 }
130 } finally {
131 setClosedInternal(true);
132 }
133 }
134 }
135
136
137
138
139
140
141
142
143 public void connectionReturnedToPool() throws SQLException {
144 if (pStmtPool != null && clearStatementPoolOnReturn) {
145 try {
146 pStmtPool.clear();
147 } catch (final Exception e) {
148 throw new SQLException("Error clearing statement pool", e);
149 }
150 }
151 }
152
153
154
155
156
157
158
159
160
161 protected PStmtKey createKey(final String sql) {
162 return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull());
163 }
164
165
166
167
168
169
170
171
172
173
174
175
176 protected PStmtKey createKey(final String sql, final int autoGeneratedKeys) {
177 return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), autoGeneratedKeys);
178 }
179
180
181
182
183
184
185
186
187
188
189
190
191
192 protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency) {
193 return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), resultSetType, resultSetConcurrency);
194 }
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210 protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency,
211 final int resultSetHoldability) {
212 return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), resultSetType, resultSetConcurrency,
213 resultSetHoldability);
214 }
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232 protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency,
233 final int resultSetHoldability, final StatementType statementType) {
234 return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), resultSetType, resultSetConcurrency,
235 resultSetHoldability, statementType);
236 }
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252 protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency,
253 final StatementType statementType) {
254 return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), resultSetType, resultSetConcurrency, statementType);
255 }
256
257
258
259
260
261
262
263
264
265
266
267
268 protected PStmtKey createKey(final String sql, final int[] columnIndexes) {
269 return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), columnIndexes);
270 }
271
272
273
274
275
276
277
278
279
280
281
282 protected PStmtKey createKey(final String sql, final StatementType statementType) {
283 return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), statementType, null);
284 }
285
286
287
288
289
290
291
292
293
294
295
296 protected PStmtKey createKey(final String sql, final String[] columnNames) {
297 return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), columnNames);
298 }
299
300
301
302
303
304
305
306
307
308
309 @Override
310 public void destroyObject(final PStmtKey key, final PooledObject<DelegatingPreparedStatement> pooledObject) throws SQLException {
311 if (pooledObject != null) {
312 @SuppressWarnings("resource")
313 final DelegatingPreparedStatement object = pooledObject.getObject();
314 if (object != null) {
315 @SuppressWarnings("resource")
316 final Statement innermostDelegate = object.getInnermostDelegate();
317 if (innermostDelegate != null) {
318 innermostDelegate.close();
319 }
320 }
321 }
322 }
323
324 private String getCatalogOrNull() {
325 try {
326 return getCatalog();
327 } catch (final SQLException ignored) {
328 return null;
329 }
330 }
331
332 private String getSchemaOrNull() {
333 try {
334 return getSchema();
335 } catch (final SQLException ignored) {
336 return null;
337 }
338 }
339
340
341
342
343
344
345
346 public KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> getStatementPool() {
347 return pStmtPool;
348 }
349
350
351
352
353
354
355
356
357
358
359 @SuppressWarnings("resource")
360 @Override
361 public PooledObject<DelegatingPreparedStatement> makeObject(final PStmtKey key) throws SQLException {
362 if (null == key) {
363 throw new IllegalArgumentException("Prepared statement key is null or invalid.");
364 }
365 if (key.getStmtType() == StatementType.PREPARED_STATEMENT) {
366 final PreparedStatement statement = (PreparedStatement) key.createStatement(getDelegate());
367 @SuppressWarnings({"rawtypes", "unchecked" })
368 final PoolablePreparedStatement pps = new PoolablePreparedStatement(statement, key, pStmtPool, this);
369 return new DefaultPooledObject<>(pps);
370 }
371 final CallableStatement statement = (CallableStatement) key.createStatement(getDelegate());
372 final PoolableCallableStatement pcs = new PoolableCallableStatement(statement, key, pStmtPool, this);
373 return new DefaultPooledObject<>(pcs);
374 }
375
376
377
378
379
380
381
382
383 protected String normalizeSQL(final String sql) {
384 return sql.trim();
385 }
386
387
388
389
390
391
392
393
394
395
396 @Override
397 public void passivateObject(final PStmtKey key, final PooledObject<DelegatingPreparedStatement> pooledObject)
398 throws SQLException {
399 @SuppressWarnings("resource")
400 final DelegatingPreparedStatement dps = pooledObject.getObject();
401 dps.clearParameters();
402 dps.passivate();
403 }
404
405
406
407
408
409
410
411
412
413
414 private CallableStatement prepareCall(final PStmtKey key) throws SQLException {
415 return (CallableStatement) prepareStatement(key);
416 }
417
418
419
420
421
422
423
424
425
426
427 @Override
428 public CallableStatement prepareCall(final String sql) throws SQLException {
429 return prepareCall(createKey(sql, StatementType.CALLABLE_STATEMENT));
430 }
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445 @Override
446 public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency)
447 throws SQLException {
448 return prepareCall(createKey(sql, resultSetType, resultSetConcurrency, StatementType.CALLABLE_STATEMENT));
449 }
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466 @Override
467 public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency,
468 final int resultSetHoldability) throws SQLException {
469 return prepareCall(createKey(sql, resultSetType, resultSetConcurrency,
470 resultSetHoldability, StatementType.CALLABLE_STATEMENT));
471 }
472
473
474
475
476
477
478
479
480
481
482 private PreparedStatement prepareStatement(final PStmtKey key) throws SQLException {
483 if (null == pStmtPool) {
484 throw new SQLException("Statement pool is null - closed or invalid PoolingConnection.");
485 }
486 try {
487 return pStmtPool.borrowObject(key);
488 } catch (final NoSuchElementException e) {
489 throw new SQLException("MaxOpenPreparedStatements limit reached", e);
490 } catch (final RuntimeException e) {
491 throw e;
492 } catch (final Exception e) {
493 throw new SQLException("Borrow prepareStatement from pool failed", e);
494 }
495 }
496
497
498
499
500
501
502
503
504
505
506 @Override
507 public PreparedStatement prepareStatement(final String sql) throws SQLException {
508 return prepareStatement(createKey(sql));
509 }
510
511
512
513
514
515
516
517
518
519
520
521
522
523 @Override
524 public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException {
525 return prepareStatement(createKey(sql, autoGeneratedKeys));
526 }
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541 @Override
542 public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency)
543 throws SQLException {
544 return prepareStatement(createKey(sql, resultSetType, resultSetConcurrency));
545 }
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562 @Override
563 public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency,
564 final int resultSetHoldability) throws SQLException {
565 return prepareStatement(createKey(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
566 }
567
568
569
570
571
572
573
574
575
576
577
578
579
580 @Override
581 public PreparedStatement prepareStatement(final String sql, final int[] columnIndexes) throws SQLException {
582 return prepareStatement(createKey(sql, columnIndexes));
583 }
584
585
586
587
588
589
590
591
592
593
594
595
596 @Override
597 public PreparedStatement prepareStatement(final String sql, final String[] columnNames) throws SQLException {
598 return prepareStatement(createKey(sql, columnNames));
599 }
600
601
602
603
604
605
606
607
608 public void setClearStatementPoolOnReturn(final boolean clearStatementPoolOnReturn) {
609 this.clearStatementPoolOnReturn = clearStatementPoolOnReturn;
610 }
611
612
613
614
615
616
617
618 public void setStatementPool(final KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> pool) {
619 pStmtPool = pool;
620 }
621
622 @Override
623 public synchronized String toString() {
624 if (pStmtPool instanceof GenericKeyedObjectPool) {
625
626 final GenericKeyedObjectPool<?, ?> gkop = (GenericKeyedObjectPool<?, ?>) pStmtPool;
627 if (gkop.getFactory() == this) {
628 return "PoolingConnection: " + pStmtPool.getClass() + "@" + System.identityHashCode(pStmtPool);
629 }
630 }
631 return "PoolingConnection: " + Objects.toString(pStmtPool);
632 }
633
634
635
636
637
638
639
640
641
642
643 @Override
644 public boolean validateObject(final PStmtKey key, final PooledObject<DelegatingPreparedStatement> pooledObject) {
645 return true;
646 }
647 }