001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.commons.dbcp;
019:
020: import java.sql.CallableStatement;
021: import java.sql.Connection;
022: import java.sql.DatabaseMetaData;
023: import java.sql.PreparedStatement;
024: import java.sql.SQLException;
025: import java.sql.SQLWarning;
026: import java.sql.Statement;
027: import java.util.List;
028: import java.util.Map;
029:
030: /**
031: * A base delegating implementation of {@link Connection}.
032: * <p>
033: * All of the methods from the {@link Connection} interface
034: * simply check to see that the {@link Connection} is active,
035: * and call the corresponding method on the "delegate"
036: * provided in my constructor.
037: * <p>
038: * Extends AbandonedTrace to implement Connection tracking and
039: * logging of code which created the Connection. Tracking the
040: * Connection ensures that the AbandonedObjectPool can close
041: * this connection and recycle it if its pool of connections
042: * is nearing exhaustion and this connection's last usage is
043: * older than the removeAbandonedTimeout.
044: *
045: * @author Rodney Waldhoff
046: * @author Glenn L. Nielsen
047: * @author James House
048: * @author Dirk Verbeeck
049: * @version $Revision: 500687 $ $Date: 2007-01-27 16:33:47 -0700 (Sat, 27 Jan 2007) $
050: */
051: public class DelegatingConnection extends AbandonedTrace implements
052: Connection {
053: /** My delegate {@link Connection}. */
054: protected Connection _conn = null;
055:
056: protected boolean _closed = false;
057:
058: /**
059: * Create a wrapper for the Connectin which traces this
060: * Connection in the AbandonedObjectPool.
061: *
062: * @param c the {@link Connection} to delegate all calls to.
063: */
064: public DelegatingConnection(Connection c) {
065: super ();
066: _conn = c;
067: }
068:
069: /**
070: * Create a wrapper for the Connection which traces
071: * the Statements created so that any unclosed Statements
072: * can be closed when this Connection is closed.
073: *
074: * @param c the {@link Connection} to delegate all calls to.
075: * @param config the configuration for tracing abandoned objects
076: * @deprecated AbandonedConfig is now deprecated.
077: */
078: public DelegatingConnection(Connection c, AbandonedConfig config) {
079: super (config);
080: _conn = c;
081: }
082:
083: /**
084: * Returns a string representation of the metadata associated with
085: * the innnermost delegate connection.
086: *
087: * @since 1.2.2
088: */
089: public String toString() {
090: String s = null;
091:
092: Connection c = this .getInnermostDelegate();
093: if (c != null) {
094: try {
095: if (c.isClosed()) {
096: s = "connection is closed";
097: } else {
098: DatabaseMetaData meta = c.getMetaData();
099: if (meta != null) {
100: StringBuffer sb = new StringBuffer();
101: sb.append(meta.getURL());
102: sb.append(", UserName=");
103: sb.append(meta.getUserName());
104: sb.append(", ");
105: sb.append(meta.getDriverName());
106: s = sb.toString();
107: }
108: }
109: } catch (SQLException ex) {
110: s = null;
111: }
112: }
113:
114: if (s == null) {
115: s = super .toString();
116: }
117:
118: return s;
119: }
120:
121: /**
122: * Returns my underlying {@link Connection}.
123: * @return my underlying {@link Connection}.
124: */
125: public Connection getDelegate() {
126: return _conn;
127: }
128:
129: /**
130: * Compares innermost delegate to the given connection.
131: *
132: * @param c connection to compare innermost delegate with
133: * @return true if innermost delegate equals <code>c</code>
134: * @since 1.2.2
135: */
136: public boolean innermostDelegateEquals(Connection c) {
137: Connection innerCon = getInnermostDelegate();
138: if (innerCon == null) {
139: return c == null;
140: } else {
141: return innerCon.equals(c);
142: }
143: }
144:
145: public boolean equals(Object obj) {
146: if (obj == null) {
147: return false;
148: }
149: if (obj == this ) {
150: return true;
151: }
152: Connection delegate = getInnermostDelegate();
153: if (delegate == null) {
154: return false;
155: }
156: if (obj instanceof DelegatingConnection) {
157: DelegatingConnection c = (DelegatingConnection) obj;
158: return c.innermostDelegateEquals(delegate);
159: } else {
160: return delegate.equals(obj);
161: }
162: }
163:
164: public int hashCode() {
165: Object obj = getInnermostDelegate();
166: if (obj == null) {
167: return 0;
168: }
169: return obj.hashCode();
170: }
171:
172: /**
173: * If my underlying {@link Connection} is not a
174: * <tt>DelegatingConnection</tt>, returns it,
175: * otherwise recursively invokes this method on
176: * my delegate.
177: * <p>
178: * Hence this method will return the first
179: * delegate that is not a <tt>DelegatingConnection</tt>,
180: * or <tt>null</tt> when no non-<tt>DelegatingConnection</tt>
181: * delegate can be found by transversing this chain.
182: * <p>
183: * This method is useful when you may have nested
184: * <tt>DelegatingConnection</tt>s, and you want to make
185: * sure to obtain a "genuine" {@link Connection}.
186: */
187: public Connection getInnermostDelegate() {
188: Connection c = _conn;
189: while (c != null && c instanceof DelegatingConnection) {
190: c = ((DelegatingConnection) c).getDelegate();
191: if (this == c) {
192: return null;
193: }
194: }
195: return c;
196: }
197:
198: /** Sets my delegate. */
199: public void setDelegate(Connection c) {
200: _conn = c;
201: }
202:
203: /**
204: * Closes the underlying connection, and close
205: * any Statements that were not explicitly closed.
206: */
207: public void close() throws SQLException {
208: passivate();
209: _conn.close();
210: }
211:
212: protected void handleException(SQLException e) throws SQLException {
213: throw e;
214: }
215:
216: public Statement createStatement() throws SQLException {
217: checkOpen();
218: try {
219: return new DelegatingStatement(this , _conn
220: .createStatement());
221: } catch (SQLException e) {
222: handleException(e);
223: return null;
224: }
225: }
226:
227: public Statement createStatement(int resultSetType,
228: int resultSetConcurrency) throws SQLException {
229: checkOpen();
230: try {
231: return new DelegatingStatement(this , _conn.createStatement(
232: resultSetType, resultSetConcurrency));
233: } catch (SQLException e) {
234: handleException(e);
235: return null;
236: }
237: }
238:
239: public PreparedStatement prepareStatement(String sql)
240: throws SQLException {
241: checkOpen();
242: try {
243: return new DelegatingPreparedStatement(this , _conn
244: .prepareStatement(sql));
245: } catch (SQLException e) {
246: handleException(e);
247: return null;
248: }
249: }
250:
251: public PreparedStatement prepareStatement(String sql,
252: int resultSetType, int resultSetConcurrency)
253: throws SQLException {
254: checkOpen();
255: try {
256: return new DelegatingPreparedStatement(this , _conn
257: .prepareStatement(sql, resultSetType,
258: resultSetConcurrency));
259: } catch (SQLException e) {
260: handleException(e);
261: return null;
262: }
263: }
264:
265: public CallableStatement prepareCall(String sql)
266: throws SQLException {
267: checkOpen();
268: try {
269: return new DelegatingCallableStatement(this , _conn
270: .prepareCall(sql));
271: } catch (SQLException e) {
272: handleException(e);
273: return null;
274: }
275: }
276:
277: public CallableStatement prepareCall(String sql, int resultSetType,
278: int resultSetConcurrency) throws SQLException {
279: checkOpen();
280: try {
281: return new DelegatingCallableStatement(this , _conn
282: .prepareCall(sql, resultSetType,
283: resultSetConcurrency));
284: } catch (SQLException e) {
285: handleException(e);
286: return null;
287: }
288: }
289:
290: public void clearWarnings() throws SQLException {
291: checkOpen();
292: try {
293: _conn.clearWarnings();
294: } catch (SQLException e) {
295: handleException(e);
296: }
297: }
298:
299: public void commit() throws SQLException {
300: checkOpen();
301: try {
302: _conn.commit();
303: } catch (SQLException e) {
304: handleException(e);
305: }
306: }
307:
308: public boolean getAutoCommit() throws SQLException {
309: checkOpen();
310: try {
311: return _conn.getAutoCommit();
312: } catch (SQLException e) {
313: handleException(e);
314: return false;
315: }
316: }
317:
318: public String getCatalog() throws SQLException {
319: checkOpen();
320: try {
321: return _conn.getCatalog();
322: } catch (SQLException e) {
323: handleException(e);
324: return null;
325: }
326: }
327:
328: public DatabaseMetaData getMetaData() throws SQLException {
329: checkOpen();
330: try {
331: return _conn.getMetaData();
332: } catch (SQLException e) {
333: handleException(e);
334: return null;
335: }
336: }
337:
338: public int getTransactionIsolation() throws SQLException {
339: checkOpen();
340: try {
341: return _conn.getTransactionIsolation();
342: } catch (SQLException e) {
343: handleException(e);
344: return -1;
345: }
346: }
347:
348: public Map getTypeMap() throws SQLException {
349: checkOpen();
350: try {
351: return _conn.getTypeMap();
352: } catch (SQLException e) {
353: handleException(e);
354: return null;
355: }
356: }
357:
358: public SQLWarning getWarnings() throws SQLException {
359: checkOpen();
360: try {
361: return _conn.getWarnings();
362: } catch (SQLException e) {
363: handleException(e);
364: return null;
365: }
366: }
367:
368: public boolean isReadOnly() throws SQLException {
369: checkOpen();
370: try {
371: return _conn.isReadOnly();
372: } catch (SQLException e) {
373: handleException(e);
374: return false;
375: }
376: }
377:
378: public String nativeSQL(String sql) throws SQLException {
379: checkOpen();
380: try {
381: return _conn.nativeSQL(sql);
382: } catch (SQLException e) {
383: handleException(e);
384: return null;
385: }
386: }
387:
388: public void rollback() throws SQLException {
389: checkOpen();
390: try {
391: _conn.rollback();
392: } catch (SQLException e) {
393: handleException(e);
394: }
395: }
396:
397: public void setAutoCommit(boolean autoCommit) throws SQLException {
398: checkOpen();
399: try {
400: _conn.setAutoCommit(autoCommit);
401: } catch (SQLException e) {
402: handleException(e);
403: }
404: }
405:
406: public void setCatalog(String catalog) throws SQLException {
407: checkOpen();
408: try {
409: _conn.setCatalog(catalog);
410: } catch (SQLException e) {
411: handleException(e);
412: }
413: }
414:
415: public void setReadOnly(boolean readOnly) throws SQLException {
416: checkOpen();
417: try {
418: _conn.setReadOnly(readOnly);
419: } catch (SQLException e) {
420: handleException(e);
421: }
422: }
423:
424: public void setTransactionIsolation(int level) throws SQLException {
425: checkOpen();
426: try {
427: _conn.setTransactionIsolation(level);
428: } catch (SQLException e) {
429: handleException(e);
430: }
431: }
432:
433: public void setTypeMap(Map map) throws SQLException {
434: checkOpen();
435: try {
436: _conn.setTypeMap(map);
437: } catch (SQLException e) {
438: handleException(e);
439: }
440: }
441:
442: public boolean isClosed() throws SQLException {
443: if (_closed || _conn.isClosed()) {
444: return true;
445: }
446: return false;
447: }
448:
449: protected void checkOpen() throws SQLException {
450: if (_closed) {
451: throw new SQLException("Connection " + _conn
452: + " is closed.");
453: }
454: }
455:
456: protected void activate() {
457: _closed = false;
458: setLastUsed();
459: if (_conn instanceof DelegatingConnection) {
460: ((DelegatingConnection) _conn).activate();
461: }
462: }
463:
464: protected void passivate() throws SQLException {
465: try {
466: // The JDBC spec requires that a Connection close any open
467: // Statement's when it is closed.
468: List statements = getTrace();
469: if (statements != null) {
470: Statement[] set = new Statement[statements.size()];
471: statements.toArray(set);
472: for (int i = 0; i < set.length; i++) {
473: set[i].close();
474: }
475: clearTrace();
476: }
477: setLastUsed(0);
478: if (_conn instanceof DelegatingConnection) {
479: ((DelegatingConnection) _conn).passivate();
480: }
481: } finally {
482: _closed = true;
483: }
484: }
485:
486: // ------------------- JDBC 3.0 -----------------------------------------
487: // Will be commented by the build process on a JDBC 2.0 system
488:
489: /* JDBC_3_ANT_KEY_BEGIN */
490:
491: public int getHoldability() throws SQLException {
492: checkOpen();
493: try {
494: return _conn.getHoldability();
495: } catch (SQLException e) {
496: handleException(e);
497: return 0;
498: }
499: }
500:
501: public void setHoldability(int holdability) throws SQLException {
502: checkOpen();
503: try {
504: _conn.setHoldability(holdability);
505: } catch (SQLException e) {
506: handleException(e);
507: }
508: }
509:
510: public java.sql.Savepoint setSavepoint() throws SQLException {
511: checkOpen();
512: try {
513: return _conn.setSavepoint();
514: } catch (SQLException e) {
515: handleException(e);
516: return null;
517: }
518: }
519:
520: public java.sql.Savepoint setSavepoint(String name)
521: throws SQLException {
522: checkOpen();
523: try {
524: return _conn.setSavepoint(name);
525: } catch (SQLException e) {
526: handleException(e);
527: return null;
528: }
529: }
530:
531: public void rollback(java.sql.Savepoint savepoint)
532: throws SQLException {
533: checkOpen();
534: try {
535: _conn.rollback(savepoint);
536: } catch (SQLException e) {
537: handleException(e);
538: }
539: }
540:
541: public void releaseSavepoint(java.sql.Savepoint savepoint)
542: throws SQLException {
543: checkOpen();
544: try {
545: _conn.releaseSavepoint(savepoint);
546: } catch (SQLException e) {
547: handleException(e);
548: }
549: }
550:
551: public Statement createStatement(int resultSetType,
552: int resultSetConcurrency, int resultSetHoldability)
553: throws SQLException {
554: checkOpen();
555: try {
556: return new DelegatingStatement(this , _conn.createStatement(
557: resultSetType, resultSetConcurrency,
558: resultSetHoldability));
559: } catch (SQLException e) {
560: handleException(e);
561: return null;
562: }
563: }
564:
565: public PreparedStatement prepareStatement(String sql,
566: int resultSetType, int resultSetConcurrency,
567: int resultSetHoldability) throws SQLException {
568: checkOpen();
569: try {
570: return new DelegatingPreparedStatement(this , _conn
571: .prepareStatement(sql, resultSetType,
572: resultSetConcurrency, resultSetHoldability));
573: } catch (SQLException e) {
574: handleException(e);
575: return null;
576: }
577: }
578:
579: public CallableStatement prepareCall(String sql, int resultSetType,
580: int resultSetConcurrency, int resultSetHoldability)
581: throws SQLException {
582: checkOpen();
583: try {
584: return new DelegatingCallableStatement(this , _conn
585: .prepareCall(sql, resultSetType,
586: resultSetConcurrency, resultSetHoldability));
587: } catch (SQLException e) {
588: handleException(e);
589: return null;
590: }
591: }
592:
593: public PreparedStatement prepareStatement(String sql,
594: int autoGeneratedKeys) throws SQLException {
595: checkOpen();
596: try {
597: return new DelegatingPreparedStatement(this , _conn
598: .prepareStatement(sql, autoGeneratedKeys));
599: } catch (SQLException e) {
600: handleException(e);
601: return null;
602: }
603: }
604:
605: public PreparedStatement prepareStatement(String sql,
606: int columnIndexes[]) throws SQLException {
607: checkOpen();
608: try {
609: return new DelegatingPreparedStatement(this , _conn
610: .prepareStatement(sql, columnIndexes));
611: } catch (SQLException e) {
612: handleException(e);
613: return null;
614: }
615: }
616:
617: public PreparedStatement prepareStatement(String sql,
618: String columnNames[]) throws SQLException {
619: checkOpen();
620: try {
621: return new DelegatingPreparedStatement(this , _conn
622: .prepareStatement(sql, columnNames));
623: } catch (SQLException e) {
624: handleException(e);
625: return null;
626: }
627: }
628: /* JDBC_3_ANT_KEY_END */
629: }
|