1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.dbcp.cpdsadapter;
19
20 import java.sql.Connection;
21 import java.sql.PreparedStatement;
22 import java.sql.SQLException;
23 import java.util.Arrays;
24 import java.util.Vector;
25
26 import javax.sql.ConnectionEvent;
27 import javax.sql.ConnectionEventListener;
28 import javax.sql.PooledConnection;
29
30 import javax.sql.StatementEventListener;
31
32
33 import org.apache.commons.dbcp.DelegatingConnection;
34 import org.apache.commons.dbcp.DelegatingPreparedStatement;
35 import org.apache.commons.dbcp.SQLNestedException;
36 import org.apache.commons.pool.KeyedObjectPool;
37 import org.apache.commons.pool.KeyedPoolableObjectFactory;
38
39
40
41
42
43
44
45
46 class PooledConnectionImpl
47 implements PooledConnection, KeyedPoolableObjectFactory {
48 private static final String CLOSED
49 = "Attempted to use PooledConnection after closed() was called.";
50
51
52
53
54 private Connection connection = null;
55
56
57
58
59 private final DelegatingConnection delegatingConnection;
60
61
62
63
64 private Connection logicalConnection = null;
65
66
67
68
69 private final Vector eventListeners;
70
71
72
73
74 private final Vector statementEventListeners = new Vector();
75
76
77
78
79 boolean isClosed;
80
81
82
83 protected KeyedObjectPool pstmtPool = null;
84
85
86
87
88 private boolean accessToUnderlyingConnectionAllowed = false;
89
90
91
92
93
94
95 PooledConnectionImpl(Connection connection, KeyedObjectPool pool) {
96 this.connection = connection;
97 if (connection instanceof DelegatingConnection) {
98 this.delegatingConnection = (DelegatingConnection) connection;
99 } else {
100 this.delegatingConnection = new DelegatingConnection(connection);
101 }
102 eventListeners = new Vector();
103 isClosed = false;
104 if (pool != null) {
105 pstmtPool = pool;
106 pstmtPool.setFactory(this);
107 }
108 }
109
110
111
112
113 public void addConnectionEventListener(ConnectionEventListener listener) {
114 if (!eventListeners.contains(listener)) {
115 eventListeners.add(listener);
116 }
117 }
118
119
120 public void addStatementEventListener(StatementEventListener listener) {
121 if (!statementEventListeners.contains(listener)) {
122 statementEventListeners.add(listener);
123 }
124 }
125
126
127
128
129
130
131
132
133
134 public void close() throws SQLException {
135 assertOpen();
136 isClosed = true;
137 try {
138 if (pstmtPool != null) {
139 try {
140 pstmtPool.close();
141 } finally {
142 pstmtPool = null;
143 }
144 }
145 } catch (RuntimeException e) {
146 throw e;
147 } catch (Exception e) {
148 throw new SQLNestedException("Cannot close connection (return to pool failed)", e);
149 } finally {
150 try {
151 connection.close();
152 } finally {
153 connection = null;
154 }
155 }
156 }
157
158
159
160
161 private void assertOpen() throws SQLException {
162 if (isClosed) {
163 throw new SQLException(CLOSED);
164 }
165 }
166
167
168
169
170
171
172
173 public Connection getConnection() throws SQLException {
174 assertOpen();
175
176 if (logicalConnection != null && !logicalConnection.isClosed()) {
177
178
179 throw new SQLException("PooledConnection was reused, without"
180 + "its previous Connection being closed.");
181 }
182
183
184 logicalConnection = new ConnectionImpl(
185 this, connection, isAccessToUnderlyingConnectionAllowed());
186 return logicalConnection;
187 }
188
189
190
191
192 public void removeConnectionEventListener(
193 ConnectionEventListener listener) {
194 eventListeners.remove(listener);
195 }
196
197
198 public void removeStatementEventListener(StatementEventListener listener) {
199 statementEventListeners.remove(listener);
200 }
201
202
203
204
205
206
207 protected void finalize() throws Throwable {
208
209
210 try {
211 connection.close();
212 } catch (Exception ignored) {
213 }
214
215
216 if (logicalConnection != null && !logicalConnection.isClosed()) {
217 throw new SQLException("PooledConnection was gc'ed, without"
218 + "its last Connection being closed.");
219 }
220 }
221
222
223
224
225 void notifyListeners() {
226 ConnectionEvent event = new ConnectionEvent(this);
227 Object[] listeners = eventListeners.toArray();
228 for (int i = 0; i < listeners.length; i++) {
229 ((ConnectionEventListener) listeners[i]).connectionClosed(event);
230 }
231 }
232
233
234
235
236
237
238
239
240
241 PreparedStatement prepareStatement(String sql) throws SQLException {
242 if (pstmtPool == null) {
243 return connection.prepareStatement(sql);
244 } else {
245 try {
246 return (PreparedStatement)
247 pstmtPool.borrowObject(createKey(sql));
248 } catch (RuntimeException e) {
249 throw e;
250 } catch (Exception e) {
251 throw new SQLNestedException("Borrow prepareStatement from pool failed", e);
252 }
253 }
254 }
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272 PreparedStatement prepareStatement(String sql, int resultSetType,
273 int resultSetConcurrency)
274 throws SQLException {
275 if (pstmtPool == null) {
276 return connection.prepareStatement(sql, resultSetType, resultSetConcurrency);
277 } else {
278 try {
279 return (PreparedStatement) pstmtPool.borrowObject(
280 createKey(sql,resultSetType,resultSetConcurrency));
281 } catch (RuntimeException e) {
282 throw e;
283 } catch (Exception e) {
284 throw new SQLNestedException("Borrow prepareStatement from pool failed", e);
285 }
286 }
287 }
288
289
290
291
292
293
294
295
296
297
298
299
300 PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
301 throws SQLException {
302 if (pstmtPool == null) {
303 return connection.prepareStatement(sql, autoGeneratedKeys);
304 } else {
305 try {
306 return (PreparedStatement) pstmtPool.borrowObject(
307 createKey(sql,autoGeneratedKeys));
308 } catch (RuntimeException e) {
309 throw e;
310 } catch (Exception e) {
311 throw new SQLNestedException("Borrow prepareStatement from pool failed", e);
312 }
313 }
314 }
315
316 PreparedStatement prepareStatement(String sql, int resultSetType,
317 int resultSetConcurrency, int resultSetHoldability)
318 throws SQLException {
319 if (pstmtPool == null) {
320 return connection.prepareStatement(sql, resultSetType,
321 resultSetConcurrency, resultSetHoldability);
322 } else {
323 try {
324 return (PreparedStatement) pstmtPool.borrowObject(
325 createKey(sql, resultSetType, resultSetConcurrency,
326 resultSetHoldability));
327 } catch (RuntimeException e) {
328 throw e;
329 } catch (Exception e) {
330 throw new SQLNestedException("Borrow prepareStatement from pool failed", e);
331 }
332 }
333 }
334
335 PreparedStatement prepareStatement(String sql, int columnIndexes[])
336 throws SQLException {
337 if (pstmtPool == null) {
338 return connection.prepareStatement(sql, columnIndexes);
339 } else {
340 try {
341 return (PreparedStatement) pstmtPool.borrowObject(
342 createKey(sql, columnIndexes));
343 } catch (RuntimeException e) {
344 throw e;
345 } catch (Exception e) {
346 throw new SQLNestedException("Borrow prepareStatement from pool failed", e);
347 }
348 }
349 }
350
351 PreparedStatement prepareStatement(String sql, String columnNames[])
352 throws SQLException {
353 if (pstmtPool == null) {
354 return connection.prepareStatement(sql, columnNames);
355 } else {
356 try {
357 return (PreparedStatement) pstmtPool.borrowObject(
358 createKey(sql, columnNames));
359 } catch (RuntimeException e) {
360 throw e;
361 } catch (Exception e) {
362 throw new SQLNestedException("Borrow prepareStatement from pool failed", e);
363 }
364 }
365 }
366
367
368
369
370 protected Object createKey(String sql, int autoGeneratedKeys) {
371 return new PStmtKey(normalizeSQL(sql), autoGeneratedKeys);
372 }
373
374
375
376
377 protected Object createKey(String sql, int resultSetType,
378 int resultSetConcurrency, int resultSetHoldability) {
379 return new PStmtKey(normalizeSQL(sql), resultSetType,
380 resultSetConcurrency, resultSetHoldability);
381 }
382
383
384
385
386 protected Object createKey(String sql, int columnIndexes[]) {
387 return new PStmtKey(normalizeSQL(sql), columnIndexes);
388 }
389
390
391
392
393 protected Object createKey(String sql, String columnNames[]) {
394 return new PStmtKey(normalizeSQL(sql), columnNames);
395 }
396
397
398
399
400 protected Object createKey(String sql, int resultSetType,
401 int resultSetConcurrency) {
402 return new PStmtKey(normalizeSQL(sql), resultSetType,
403 resultSetConcurrency);
404 }
405
406
407
408
409 protected Object createKey(String sql) {
410 return new PStmtKey(normalizeSQL(sql));
411 }
412
413
414
415
416
417 protected String normalizeSQL(String sql) {
418 return sql.trim();
419 }
420
421
422
423
424
425
426 public Object makeObject(Object obj) throws Exception {
427 if (null == obj || !(obj instanceof PStmtKey)) {
428 throw new IllegalArgumentException();
429 } else {
430
431 PStmtKey key = (PStmtKey)obj;
432 if (null == key._resultSetType
433 && null == key._resultSetConcurrency) {
434 if (null == key._autoGeneratedKeys) {
435 return new PoolablePreparedStatementStub(
436 connection.prepareStatement(key._sql),
437 key, pstmtPool, delegatingConnection);
438 } else {
439 return new PoolablePreparedStatementStub(
440 connection.prepareStatement(key._sql,
441 key._autoGeneratedKeys.intValue()),
442 key, pstmtPool, delegatingConnection);
443 }
444 } else {
445 return new PoolablePreparedStatementStub(
446 connection.prepareStatement(key._sql,
447 key._resultSetType.intValue(),
448 key._resultSetConcurrency.intValue()),
449 key, pstmtPool, delegatingConnection);
450 }
451 }
452 }
453
454
455
456
457
458
459
460 public void destroyObject(Object key, Object obj) throws Exception {
461
462 if (obj instanceof DelegatingPreparedStatement) {
463 ((DelegatingPreparedStatement) obj).getInnermostDelegate().close();
464 } else {
465 ((PreparedStatement) obj).close();
466 }
467 }
468
469
470
471
472
473
474
475
476 public boolean validateObject(Object key, Object obj) {
477 return true;
478 }
479
480
481
482
483
484
485
486 public void activateObject(Object key, Object obj) throws Exception {
487 ((PoolablePreparedStatementStub) obj).activate();
488 }
489
490
491
492
493
494
495
496 public void passivateObject(Object key, Object obj) throws Exception {
497 ((PreparedStatement) obj).clearParameters();
498 ((PoolablePreparedStatementStub) obj).passivate();
499 }
500
501
502
503
504
505
506 public synchronized boolean isAccessToUnderlyingConnectionAllowed() {
507 return this.accessToUnderlyingConnectionAllowed;
508 }
509
510
511
512
513
514
515
516
517 public synchronized void setAccessToUnderlyingConnectionAllowed(boolean allow) {
518 this.accessToUnderlyingConnectionAllowed = allow;
519 }
520
521
522
523
524 static class PStmtKey {
525 protected String _sql = null;
526 protected Integer _resultSetType = null;
527 protected Integer _resultSetConcurrency = null;
528 protected Integer _autoGeneratedKeys = null;
529 protected Integer _resultSetHoldability = null;
530 protected int _columnIndexes[] = null;
531 protected String _columnNames[] = null;
532
533 PStmtKey(String sql) {
534 _sql = sql;
535 }
536
537 PStmtKey(String sql, int resultSetType, int resultSetConcurrency) {
538 _sql = sql;
539 _resultSetType = new Integer(resultSetType);
540 _resultSetConcurrency = new Integer(resultSetConcurrency);
541 }
542
543 PStmtKey(String sql, int autoGeneratedKeys) {
544 _sql = sql;
545 _autoGeneratedKeys = new Integer(autoGeneratedKeys);
546 }
547
548 PStmtKey(String sql, int resultSetType, int resultSetConcurrency,
549 int resultSetHoldability) {
550 _sql = sql;
551 _resultSetType = new Integer(resultSetType);
552 _resultSetConcurrency = new Integer(resultSetConcurrency);
553 _resultSetHoldability = new Integer(resultSetHoldability);
554 }
555
556 PStmtKey(String sql, int columnIndexes[]) {
557 _sql = sql;
558 _columnIndexes = columnIndexes;
559 }
560
561 PStmtKey(String sql, String columnNames[]) {
562 _sql = sql;
563 _columnNames = columnNames;
564 }
565
566
567 public boolean equals(Object that) {
568 try {
569 PStmtKey key = (PStmtKey) that;
570 return(((null == _sql && null == key._sql) || _sql.equals(key._sql)) &&
571 ((null == _resultSetType && null == key._resultSetType) || _resultSetType.equals(key._resultSetType)) &&
572 ((null == _resultSetConcurrency && null == key._resultSetConcurrency) || _resultSetConcurrency.equals(key._resultSetConcurrency)) &&
573 ((null == _autoGeneratedKeys && null == key._autoGeneratedKeys) || _autoGeneratedKeys.equals(key._autoGeneratedKeys)) &&
574 ((null == _resultSetHoldability && null == key._resultSetHoldability) || _resultSetHoldability.equals(key._resultSetHoldability)) &&
575 ((null == _columnIndexes && null == key._columnIndexes) || Arrays.equals(_columnIndexes, key._columnIndexes)) &&
576 ((null == _columnNames && null == key._columnNames) || Arrays.equals(_columnNames, key._columnNames))
577 );
578 } catch (ClassCastException e) {
579 return false;
580 } catch (NullPointerException e) {
581 return false;
582 }
583 }
584
585 public int hashCode() {
586 return(null == _sql ? 0 : _sql.hashCode());
587 }
588
589 public String toString() {
590 StringBuffer buf = new StringBuffer();
591 buf.append("PStmtKey: sql=");
592 buf.append(_sql);
593 buf.append(", resultSetType=");
594 buf.append(_resultSetType);
595 buf.append(", resultSetConcurrency=");
596 buf.append(_resultSetConcurrency);
597 buf.append(", autoGeneratedKeys=");
598 buf.append(_autoGeneratedKeys);
599 buf.append(", resultSetHoldability=");
600 buf.append(_resultSetHoldability);
601 buf.append(", columnIndexes=");
602
603 arrayToString(buf,_columnIndexes);
604 buf.append(", columnNames=");
605
606 arrayToString(buf,_columnNames);
607 return buf.toString();
608 }
609 private void arrayToString(StringBuffer sb, int[] array){
610 if (array == null) {
611 sb.append("null");
612 return;
613 }
614 sb.append('[');
615 for(int i=0; i<array.length; i++){
616 if (i>0){
617 sb.append(',');
618 }
619 sb.append(array[i]);
620 }
621 sb.append(']');
622 }
623 private void arrayToString(StringBuffer sb, String[] array){
624 if (array == null) {
625 sb.append("null");
626 return;
627 }
628 sb.append('[');
629 for(int i=0; i<array.length; i++){
630 if (i>0){
631 sb.append(',');
632 }
633 sb.append(array[i]);
634 }
635 sb.append(']');
636 }
637 }
638 }