1. /*
  2. * Copyright 1999-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.apache.commons.dbcp;
  17. import java.sql.CallableStatement;
  18. import java.sql.Connection;
  19. import java.sql.DatabaseMetaData;
  20. import java.sql.PreparedStatement;
  21. import java.sql.SQLException;
  22. import java.sql.SQLWarning;
  23. import java.sql.Statement;
  24. import java.util.List;
  25. import java.util.Map;
  26. /**
  27. * A base delegating implementation of {@link Connection}.
  28. * <p>
  29. * All of the methods from the {@link Connection} interface
  30. * simply check to see that the {@link Connection} is active,
  31. * and call the corresponding method on the "delegate"
  32. * provided in my constructor.
  33. * <p>
  34. * Extends AbandonedTrace to implement Connection tracking and
  35. * logging of code which created the Connection. Tracking the
  36. * Connection ensures that the AbandonedObjectPool can close
  37. * this connection and recycle it if its pool of connections
  38. * is nearing exhaustion and this connection's last usage is
  39. * older than the removeAbandonedTimeout.
  40. *
  41. * @author Rodney Waldhoff
  42. * @author Glenn L. Nielsen
  43. * @author James House
  44. * @author Dirk Verbeeck
  45. * @version $Revision: 1.19 $ $Date: 2004/03/06 13:35:31 $
  46. */
  47. public class DelegatingConnection extends AbandonedTrace
  48. implements Connection {
  49. /** My delegate {@link Connection}. */
  50. protected Connection _conn = null;
  51. protected boolean _closed = false;
  52. /**
  53. * Create a wrapper for the Connectin which traces this
  54. * Connection in the AbandonedObjectPool.
  55. *
  56. * @param c the {@link Connection} to delegate all calls to.
  57. */
  58. public DelegatingConnection(Connection c) {
  59. super();
  60. _conn = c;
  61. }
  62. /**
  63. * Create a wrapper for the Connection which traces
  64. * the Statements created so that any unclosed Statements
  65. * can be closed when this Connection is closed.
  66. *
  67. * @param Connection the {@link Connection} to delegate all calls to.
  68. * @param AbandonedConfig the configuration for tracing abandoned objects
  69. * @deprecated AbandonedConfig is now deprecated.
  70. */
  71. public DelegatingConnection(Connection c, AbandonedConfig config) {
  72. super(config);
  73. _conn = c;
  74. }
  75. /**
  76. * Returns my underlying {@link Connection}.
  77. * @return my underlying {@link Connection}.
  78. */
  79. public Connection getDelegate() {
  80. return _conn;
  81. }
  82. public boolean equals(Object obj) {
  83. Connection delegate = getInnermostDelegate();
  84. if (delegate == null) {
  85. return false;
  86. }
  87. if (obj instanceof DelegatingConnection) {
  88. DelegatingConnection c = (DelegatingConnection) obj;
  89. return delegate.equals(c.getInnermostDelegate());
  90. }
  91. else {
  92. return delegate.equals(obj);
  93. }
  94. }
  95. public int hashCode() {
  96. Object obj = getInnermostDelegate();
  97. if (obj == null) {
  98. return 0;
  99. }
  100. return obj.hashCode();
  101. }
  102. /**
  103. * If my underlying {@link Connection} is not a
  104. * <tt>DelegatingConnection</tt>, returns it,
  105. * otherwise recursively invokes this method on
  106. * my delegate.
  107. * <p>
  108. * Hence this method will return the first
  109. * delegate that is not a <tt>DelegatingConnection</tt>,
  110. * or <tt>null</tt> when no non-<tt>DelegatingConnection</tt>
  111. * delegate can be found by transversing this chain.
  112. * <p>
  113. * This method is useful when you may have nested
  114. * <tt>DelegatingConnection</tt>s, and you want to make
  115. * sure to obtain a "genuine" {@link Connection}.
  116. */
  117. public Connection getInnermostDelegate() {
  118. Connection c = _conn;
  119. while(c != null && c instanceof DelegatingConnection) {
  120. c = ((DelegatingConnection)c).getDelegate();
  121. if(this == c) {
  122. return null;
  123. }
  124. }
  125. return c;
  126. }
  127. /** Sets my delegate. */
  128. public void setDelegate(Connection c) {
  129. _conn = c;
  130. }
  131. /**
  132. * Closes the underlying connection, and close
  133. * any Statements that were not explicitly closed.
  134. */
  135. public void close() throws SQLException
  136. {
  137. passivate();
  138. _conn.close();
  139. }
  140. protected void handleException(SQLException e) throws SQLException {
  141. throw e;
  142. }
  143. public Statement createStatement() throws SQLException {
  144. checkOpen();
  145. try {
  146. return new DelegatingStatement(this, _conn.createStatement());
  147. }
  148. catch (SQLException e) {
  149. handleException(e);
  150. return null;
  151. }
  152. }
  153. public Statement createStatement(int resultSetType,
  154. int resultSetConcurrency) throws SQLException {
  155. checkOpen();
  156. try {
  157. return new DelegatingStatement
  158. (this, _conn.createStatement(resultSetType,resultSetConcurrency));
  159. }
  160. catch (SQLException e) {
  161. handleException(e);
  162. return null;
  163. }
  164. }
  165. public PreparedStatement prepareStatement(String sql) throws SQLException {
  166. checkOpen();
  167. try {
  168. return new DelegatingPreparedStatement
  169. (this, _conn.prepareStatement(sql));
  170. }
  171. catch (SQLException e) {
  172. handleException(e);
  173. return null;
  174. }
  175. }
  176. public PreparedStatement prepareStatement(String sql,
  177. int resultSetType,
  178. int resultSetConcurrency) throws SQLException {
  179. checkOpen();
  180. try {
  181. return new DelegatingPreparedStatement
  182. (this, _conn.prepareStatement
  183. (sql,resultSetType,resultSetConcurrency));
  184. }
  185. catch (SQLException e) {
  186. handleException(e);
  187. return null;
  188. }
  189. }
  190. public CallableStatement prepareCall(String sql) throws SQLException {
  191. checkOpen();
  192. try {
  193. return new DelegatingCallableStatement(this, _conn.prepareCall(sql));
  194. }
  195. catch (SQLException e) {
  196. handleException(e);
  197. return null;
  198. }
  199. }
  200. public CallableStatement prepareCall(String sql,
  201. int resultSetType,
  202. int resultSetConcurrency) throws SQLException {
  203. checkOpen();
  204. try {
  205. return new DelegatingCallableStatement
  206. (this, _conn.prepareCall(sql, resultSetType,resultSetConcurrency));
  207. }
  208. catch (SQLException e) {
  209. handleException(e);
  210. return null;
  211. }
  212. }
  213. public void clearWarnings() throws SQLException
  214. { checkOpen(); try { _conn.clearWarnings(); } catch (SQLException e) { handleException(e); } }
  215. public void commit() throws SQLException
  216. { checkOpen(); try { _conn.commit(); } catch (SQLException e) { handleException(e); } }
  217. public boolean getAutoCommit() throws SQLException
  218. { checkOpen(); try { return _conn.getAutoCommit(); } catch (SQLException e) { handleException(e); return false; }
  219. }
  220. public String getCatalog() throws SQLException
  221. { checkOpen(); try { return _conn.getCatalog(); } catch (SQLException e) { handleException(e); return null; } }
  222. public DatabaseMetaData getMetaData() throws SQLException
  223. { checkOpen(); try { return _conn.getMetaData(); } catch (SQLException e) { handleException(e); return null; } }
  224. public int getTransactionIsolation() throws SQLException
  225. { checkOpen(); try { return _conn.getTransactionIsolation(); } catch (SQLException e) { handleException(e); return -1; } }
  226. public Map getTypeMap() throws SQLException
  227. { checkOpen(); try { return _conn.getTypeMap(); } catch (SQLException e) { handleException(e); return null; } }
  228. public SQLWarning getWarnings() throws SQLException
  229. { checkOpen(); try { return _conn.getWarnings(); } catch (SQLException e) { handleException(e); return null; } }
  230. public boolean isReadOnly() throws SQLException
  231. { checkOpen(); try { return _conn.isReadOnly(); } catch (SQLException e) { handleException(e); return false; } }
  232. public String nativeSQL(String sql) throws SQLException
  233. { checkOpen(); try { return _conn.nativeSQL(sql); } catch (SQLException e) { handleException(e); return null; } }
  234. public void rollback() throws SQLException
  235. { checkOpen(); try { _conn.rollback(); } catch (SQLException e) { handleException(e); } }
  236. public void setAutoCommit(boolean autoCommit) throws SQLException
  237. { checkOpen(); try { _conn.setAutoCommit(autoCommit); } catch (SQLException e) { handleException(e); } }
  238. public void setCatalog(String catalog) throws SQLException
  239. { checkOpen(); try { _conn.setCatalog(catalog); } catch (SQLException e) { handleException(e); } }
  240. public void setReadOnly(boolean readOnly) throws SQLException
  241. { checkOpen(); try { _conn.setReadOnly(readOnly); } catch (SQLException e) { handleException(e); } }
  242. public void setTransactionIsolation(int level) throws SQLException
  243. { checkOpen(); try { _conn.setTransactionIsolation(level); } catch (SQLException e) { handleException(e); } }
  244. public void setTypeMap(Map map) throws SQLException
  245. { checkOpen(); try { _conn.setTypeMap(map); } catch (SQLException e) { handleException(e); } }
  246. public boolean isClosed() throws SQLException {
  247. if(_closed || _conn.isClosed()) {
  248. return true;
  249. }
  250. return false;
  251. }
  252. protected void checkOpen() throws SQLException {
  253. if(_closed) {
  254. throw new SQLException("Connection is closed.");
  255. }
  256. }
  257. protected void activate() {
  258. _closed = false;
  259. setLastUsed();
  260. if(_conn instanceof DelegatingConnection) {
  261. ((DelegatingConnection)_conn).activate();
  262. }
  263. }
  264. protected void passivate() throws SQLException {
  265. try {
  266. // The JDBC spec requires that a Connection close any open
  267. // Statement's when it is closed.
  268. List statements = getTrace();
  269. if( statements != null) {
  270. Statement[] set = new Statement[statements.size()];
  271. statements.toArray(set);
  272. for (int i = 0; i < set.length; i++) {
  273. set[i].close();
  274. }
  275. clearTrace();
  276. }
  277. setLastUsed(0);
  278. if(_conn instanceof DelegatingConnection) {
  279. ((DelegatingConnection)_conn).passivate();
  280. }
  281. }
  282. finally {
  283. _closed = true;
  284. }
  285. }
  286. // ------------------- JDBC 3.0 -----------------------------------------
  287. // Will be commented by the build process on a JDBC 2.0 system
  288. /* JDBC_3_ANT_KEY_BEGIN */
  289. public int getHoldability() throws SQLException
  290. { checkOpen(); try { return _conn.getHoldability(); } catch (SQLException e) { handleException(e); return 0; } }
  291. public void setHoldability(int holdability) throws SQLException
  292. { checkOpen(); try { _conn.setHoldability(holdability); } catch (SQLException e) { handleException(e); } }
  293. public java.sql.Savepoint setSavepoint() throws SQLException
  294. { checkOpen(); try { return _conn.setSavepoint(); } catch (SQLException e) { handleException(e); return null; } }
  295. public java.sql.Savepoint setSavepoint(String name) throws SQLException
  296. { checkOpen(); try { return _conn.setSavepoint(name); } catch (SQLException e) { handleException(e); return null; } }
  297. public void rollback(java.sql.Savepoint savepoint) throws SQLException
  298. { checkOpen(); try { _conn.rollback(savepoint); } catch (SQLException e) { handleException(e); } }
  299. public void releaseSavepoint(java.sql.Savepoint savepoint) throws SQLException
  300. { checkOpen(); try { _conn.releaseSavepoint(savepoint); } catch (SQLException e) { handleException(e); } }
  301. public Statement createStatement(int resultSetType,
  302. int resultSetConcurrency,
  303. int resultSetHoldability) throws SQLException {
  304. checkOpen();
  305. try {
  306. return new DelegatingStatement(this, _conn.createStatement(
  307. resultSetType, resultSetConcurrency, resultSetHoldability));
  308. }
  309. catch (SQLException e) {
  310. handleException(e);
  311. return null;
  312. }
  313. }
  314. public PreparedStatement prepareStatement(String sql, int resultSetType,
  315. int resultSetConcurrency,
  316. int resultSetHoldability) throws SQLException {
  317. checkOpen();
  318. try {
  319. return new DelegatingPreparedStatement(this, _conn.prepareStatement(
  320. sql, resultSetType, resultSetConcurrency, resultSetHoldability));
  321. }
  322. catch (SQLException e) {
  323. handleException(e);
  324. return null;
  325. }
  326. }
  327. public CallableStatement prepareCall(String sql, int resultSetType,
  328. int resultSetConcurrency,
  329. int resultSetHoldability) throws SQLException {
  330. checkOpen();
  331. try {
  332. return new DelegatingCallableStatement(this, _conn.prepareCall(
  333. sql, resultSetType, resultSetConcurrency, resultSetHoldability));
  334. }
  335. catch (SQLException e) {
  336. handleException(e);
  337. return null;
  338. }
  339. }
  340. public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
  341. checkOpen();
  342. try {
  343. return new DelegatingPreparedStatement(this, _conn.prepareStatement(
  344. sql, autoGeneratedKeys));
  345. }
  346. catch (SQLException e) {
  347. handleException(e);
  348. return null;
  349. }
  350. }
  351. public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException {
  352. checkOpen();
  353. try {
  354. return new DelegatingPreparedStatement(this, _conn.prepareStatement(
  355. sql, columnIndexes));
  356. }
  357. catch (SQLException e) {
  358. handleException(e);
  359. return null;
  360. }
  361. }
  362. public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException {
  363. checkOpen();
  364. try {
  365. return new DelegatingPreparedStatement(this, _conn.prepareStatement(
  366. sql, columnNames));
  367. }
  368. catch (SQLException e) {
  369. handleException(e);
  370. return null;
  371. }
  372. }
  373. /* JDBC_3_ANT_KEY_END */
  374. }