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