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.io.PrintWriter;
  18. import java.sql.CallableStatement;
  19. import java.sql.Connection;
  20. import java.sql.DatabaseMetaData;
  21. import java.sql.PreparedStatement;
  22. import java.sql.SQLException;
  23. import java.sql.SQLWarning;
  24. import java.sql.Statement;
  25. import java.util.Map;
  26. import java.util.NoSuchElementException;
  27. import javax.sql.DataSource;
  28. import org.apache.commons.pool.ObjectPool;
  29. /**
  30. * A simple {@link DataSource} implementation that obtains
  31. * {@link Connection}s from the specified {@link ObjectPool}.
  32. *
  33. * @author Rodney Waldhoff
  34. * @author Glenn L. Nielsen
  35. * @author James House
  36. * @author Dirk Verbeeck
  37. * @version $Revision: 1.13 $ $Date: 2004/02/28 12:18:17 $
  38. */
  39. public class PoolingDataSource implements DataSource {
  40. /** Controls access to the underlying connection */
  41. private boolean accessToUnderlyingConnectionAllowed = false;
  42. public PoolingDataSource() {
  43. this(null);
  44. }
  45. public PoolingDataSource(ObjectPool pool) {
  46. _pool = pool;
  47. }
  48. public void setPool(ObjectPool pool) throws IllegalStateException, NullPointerException {
  49. if(null != _pool) {
  50. throw new IllegalStateException("Pool already set");
  51. } else if(null == pool) {
  52. throw new NullPointerException("Pool must not be null.");
  53. } else {
  54. _pool = pool;
  55. }
  56. }
  57. /**
  58. * Returns the value of the accessToUnderlyingConnectionAllowed property.
  59. *
  60. * @return true if access to the underlying is allowed, false otherwise.
  61. */
  62. public boolean isAccessToUnderlyingConnectionAllowed() {
  63. return this.accessToUnderlyingConnectionAllowed;
  64. }
  65. /**
  66. * Sets the value of the accessToUnderlyingConnectionAllowed property.
  67. * It controls if the PoolGuard allows access to the underlying connection.
  68. * (Default: false)
  69. *
  70. * @param allow Access to the underlying connection is granted when true.
  71. */
  72. public void setAccessToUnderlyingConnectionAllowed(boolean allow) {
  73. this.accessToUnderlyingConnectionAllowed = allow;
  74. }
  75. //--- DataSource methods -----------------------------------------
  76. /**
  77. * Return a {@link java.sql.Connection} from my pool,
  78. * according to the contract specified by {@link ObjectPool#borrowObject}.
  79. */
  80. public Connection getConnection() throws SQLException {
  81. try {
  82. Connection conn = (Connection)(_pool.borrowObject());
  83. if (conn != null) {
  84. conn = new PoolGuardConnectionWrapper(conn);
  85. }
  86. return conn;
  87. } catch(SQLException e) {
  88. throw e;
  89. } catch(NoSuchElementException e) {
  90. throw new SQLNestedException("Cannot get a connection, pool exhausted", e);
  91. } catch(RuntimeException e) {
  92. throw e;
  93. } catch(Exception e) {
  94. throw new SQLNestedException("Cannot get a connection, general error", e);
  95. }
  96. }
  97. /**
  98. * Throws {@link UnsupportedOperationException}
  99. * @throws UnsupportedOperationException
  100. */
  101. public Connection getConnection(String uname, String passwd) throws SQLException {
  102. throw new UnsupportedOperationException();
  103. }
  104. /**
  105. * Returns my log writer.
  106. * @return my log writer
  107. * @see DataSource#getLogWriter
  108. */
  109. public PrintWriter getLogWriter() {
  110. return _logWriter;
  111. }
  112. /**
  113. * Throws {@link UnsupportedOperationException}.
  114. * Do this configuration within my {@link ObjectPool}.
  115. * @throws UnsupportedOperationException
  116. */
  117. public int getLoginTimeout() {
  118. throw new UnsupportedOperationException();
  119. }
  120. /**
  121. * Throws {@link UnsupportedOperationException}.
  122. * Do this configuration within my {@link ObjectPool}.
  123. * @throws UnsupportedOperationException
  124. */
  125. public void setLoginTimeout(int seconds) {
  126. throw new UnsupportedOperationException();
  127. }
  128. /**
  129. * Sets my log writer.
  130. * @see DataSource#setLogWriter
  131. */
  132. public void setLogWriter(PrintWriter out) {
  133. _logWriter = out;
  134. }
  135. /** My log writer. */
  136. protected PrintWriter _logWriter = null;
  137. protected ObjectPool _pool = null;
  138. /**
  139. * PoolGuardConnectionWrapper is a Connection wrapper that makes sure a
  140. * closed connection cannot be used anymore.
  141. */
  142. private class PoolGuardConnectionWrapper extends DelegatingConnection {
  143. private Connection delegate;
  144. PoolGuardConnectionWrapper(Connection delegate) {
  145. super(delegate);
  146. this.delegate = delegate;
  147. }
  148. protected void checkOpen() throws SQLException {
  149. if(delegate == null) {
  150. throw new SQLException("Connection is closed.");
  151. }
  152. }
  153. public void close() throws SQLException {
  154. checkOpen();
  155. this.delegate.close();
  156. this.delegate = null;
  157. super.setDelegate(null);
  158. }
  159. public boolean isClosed() throws SQLException {
  160. if (delegate == null) {
  161. return true;
  162. }
  163. return delegate.isClosed();
  164. }
  165. public void clearWarnings() throws SQLException {
  166. checkOpen();
  167. delegate.clearWarnings();
  168. }
  169. public void commit() throws SQLException {
  170. checkOpen();
  171. delegate.commit();
  172. }
  173. public Statement createStatement() throws SQLException {
  174. checkOpen();
  175. return delegate.createStatement();
  176. }
  177. public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
  178. checkOpen();
  179. return delegate.createStatement(resultSetType, resultSetConcurrency);
  180. }
  181. public boolean equals(Object obj) {
  182. if (delegate == null){
  183. return false;
  184. }
  185. return delegate.equals(obj);
  186. }
  187. public boolean getAutoCommit() throws SQLException {
  188. checkOpen();
  189. return delegate.getAutoCommit();
  190. }
  191. public String getCatalog() throws SQLException {
  192. checkOpen();
  193. return delegate.getCatalog();
  194. }
  195. public DatabaseMetaData getMetaData() throws SQLException {
  196. checkOpen();
  197. return delegate.getMetaData();
  198. }
  199. public int getTransactionIsolation() throws SQLException {
  200. checkOpen();
  201. return delegate.getTransactionIsolation();
  202. }
  203. public Map getTypeMap() throws SQLException {
  204. checkOpen();
  205. return delegate.getTypeMap();
  206. }
  207. public SQLWarning getWarnings() throws SQLException {
  208. checkOpen();
  209. return delegate.getWarnings();
  210. }
  211. public int hashCode() {
  212. if (delegate == null){
  213. return 0;
  214. }
  215. return delegate.hashCode();
  216. }
  217. public boolean isReadOnly() throws SQLException {
  218. checkOpen();
  219. return delegate.isReadOnly();
  220. }
  221. public String nativeSQL(String sql) throws SQLException {
  222. checkOpen();
  223. return delegate.nativeSQL(sql);
  224. }
  225. public CallableStatement prepareCall(String sql) throws SQLException {
  226. checkOpen();
  227. return delegate.prepareCall(sql);
  228. }
  229. public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
  230. checkOpen();
  231. return delegate.prepareCall(sql, resultSetType, resultSetConcurrency);
  232. }
  233. public PreparedStatement prepareStatement(String sql) throws SQLException {
  234. checkOpen();
  235. return delegate.prepareStatement(sql);
  236. }
  237. public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
  238. checkOpen();
  239. return delegate.prepareStatement(sql, resultSetType, resultSetConcurrency);
  240. }
  241. public void rollback() throws SQLException {
  242. checkOpen();
  243. delegate.rollback();
  244. }
  245. public void setAutoCommit(boolean autoCommit) throws SQLException {
  246. checkOpen();
  247. delegate.setAutoCommit(autoCommit);
  248. }
  249. public void setCatalog(String catalog) throws SQLException {
  250. checkOpen();
  251. delegate.setCatalog(catalog);
  252. }
  253. public void setReadOnly(boolean readOnly) throws SQLException {
  254. checkOpen();
  255. delegate.setReadOnly(readOnly);
  256. }
  257. public void setTransactionIsolation(int level) throws SQLException {
  258. checkOpen();
  259. delegate.setTransactionIsolation(level);
  260. }
  261. public void setTypeMap(Map map) throws SQLException {
  262. checkOpen();
  263. delegate.setTypeMap(map);
  264. }
  265. public String toString() {
  266. if (delegate == null){
  267. return null;
  268. }
  269. return delegate.toString();
  270. }
  271. // ------------------- JDBC 3.0 -----------------------------------------
  272. // Will be commented by the build process on a JDBC 2.0 system
  273. /* JDBC_3_ANT_KEY_BEGIN */
  274. public int getHoldability() throws SQLException {
  275. checkOpen();
  276. return delegate.getHoldability();
  277. }
  278. public void setHoldability(int holdability) throws SQLException {
  279. checkOpen();
  280. delegate.setHoldability(holdability);
  281. }
  282. public java.sql.Savepoint setSavepoint() throws SQLException {
  283. checkOpen();
  284. return delegate.setSavepoint();
  285. }
  286. public java.sql.Savepoint setSavepoint(String name) throws SQLException {
  287. checkOpen();
  288. return delegate.setSavepoint(name);
  289. }
  290. public void releaseSavepoint(java.sql.Savepoint savepoint) throws SQLException {
  291. checkOpen();
  292. delegate.releaseSavepoint(savepoint);
  293. }
  294. public void rollback(java.sql.Savepoint savepoint) throws SQLException {
  295. checkOpen();
  296. delegate.rollback(savepoint);
  297. }
  298. public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
  299. checkOpen();
  300. return delegate.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
  301. }
  302. public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
  303. checkOpen();
  304. return delegate.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
  305. }
  306. public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
  307. checkOpen();
  308. return delegate.prepareStatement(sql, autoGeneratedKeys);
  309. }
  310. public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
  311. checkOpen();
  312. return delegate.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
  313. }
  314. public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
  315. checkOpen();
  316. return delegate.prepareStatement(sql, columnIndexes);
  317. }
  318. public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
  319. checkOpen();
  320. return delegate.prepareStatement(sql, columnNames);
  321. }
  322. /* JDBC_3_ANT_KEY_END */
  323. /**
  324. * @see org.apache.commons.dbcp.DelegatingConnection#getDelegate()
  325. */
  326. public Connection getDelegate() {
  327. if (isAccessToUnderlyingConnectionAllowed()) {
  328. return super.getDelegate();
  329. } else {
  330. return null;
  331. }
  332. }
  333. /**
  334. * @see org.apache.commons.dbcp.DelegatingConnection#getInnermostDelegate()
  335. */
  336. public Connection getInnermostDelegate() {
  337. if (isAccessToUnderlyingConnectionAllowed()) {
  338. return super.getInnermostDelegate();
  339. } else {
  340. return null;
  341. }
  342. }
  343. }
  344. }