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.IOException;
  18. import java.io.InputStream;
  19. import java.sql.CallableStatement;
  20. import java.sql.Connection;
  21. import java.sql.DatabaseMetaData;
  22. import java.sql.Driver;
  23. import java.sql.DriverManager;
  24. import java.sql.DriverPropertyInfo;
  25. import java.sql.PreparedStatement;
  26. import java.sql.SQLException;
  27. import java.sql.SQLWarning;
  28. import java.sql.Statement;
  29. import java.util.HashMap;
  30. import java.util.Map;
  31. import java.util.NoSuchElementException;
  32. import java.util.Properties;
  33. import java.util.Set;
  34. import org.apache.commons.jocl.JOCLContentHandler;
  35. import org.apache.commons.pool.ObjectPool;
  36. import org.xml.sax.SAXException;
  37. /**
  38. * A {@link Driver} implementation that obtains
  39. * {@link Connection}s from a registered
  40. * {@link ObjectPool}.
  41. *
  42. * @author Rodney Waldhoff
  43. * @author Dirk Verbeeck
  44. * @version $Revision: 1.12 $ $Date: 2004/05/17 18:39:44 $
  45. */
  46. public class PoolingDriver implements Driver {
  47. /** Register an myself with the {@link DriverManager}. */
  48. static {
  49. try {
  50. DriverManager.registerDriver(new PoolingDriver());
  51. } catch(Exception e) {
  52. }
  53. }
  54. /** The map of registered pools. */
  55. protected static HashMap _pools = new HashMap();
  56. /** Controls access to the underlying connection */
  57. private static boolean accessToUnderlyingConnectionAllowed = false;
  58. public PoolingDriver() {
  59. }
  60. /**
  61. * Returns the value of the accessToUnderlyingConnectionAllowed property.
  62. *
  63. * @return true if access to the underlying is allowed, false otherwise.
  64. */
  65. public static synchronized boolean isAccessToUnderlyingConnectionAllowed() {
  66. return accessToUnderlyingConnectionAllowed;
  67. }
  68. /**
  69. * Sets the value of the accessToUnderlyingConnectionAllowed property.
  70. * It controls if the PoolGuard allows access to the underlying connection.
  71. * (Default: false)
  72. *
  73. * @param allow Access to the underlying connection is granted when true.
  74. */
  75. public static synchronized void setAccessToUnderlyingConnectionAllowed(boolean allow) {
  76. accessToUnderlyingConnectionAllowed = allow;
  77. }
  78. /**
  79. * WARNING: This method throws DbcpExceptions (RuntimeExceptions)
  80. * and will be replaced by the protected getConnectionPool method.
  81. *
  82. * @deprecated This will be removed in a future version of DBCP.
  83. */
  84. public synchronized ObjectPool getPool(String name) {
  85. try {
  86. return getConnectionPool(name);
  87. }
  88. catch (Exception e) {
  89. throw new DbcpException(e);
  90. }
  91. }
  92. public synchronized ObjectPool getConnectionPool(String name) throws SQLException {
  93. ObjectPool pool = (ObjectPool)(_pools.get(name));
  94. if(null == pool) {
  95. InputStream in = this.getClass().getResourceAsStream(String.valueOf(name) + ".jocl");
  96. if(null != in) {
  97. JOCLContentHandler jocl = null;
  98. try {
  99. jocl = JOCLContentHandler.parse(in);
  100. }
  101. catch (SAXException e) {
  102. throw new SQLNestedException("Could not parse configuration file", e);
  103. }
  104. catch (IOException e) {
  105. throw new SQLNestedException("Could not load configuration file", e);
  106. }
  107. if(jocl.getType(0).equals(String.class)) {
  108. pool = getPool((String)(jocl.getValue(0)));
  109. if(null != pool) {
  110. registerPool(name,pool);
  111. }
  112. } else {
  113. pool = ((PoolableConnectionFactory)(jocl.getValue(0))).getPool();
  114. if(null != pool) {
  115. registerPool(name,pool);
  116. }
  117. }
  118. }
  119. else {
  120. throw new SQLException("Configuration file not found");
  121. }
  122. }
  123. return pool;
  124. }
  125. public synchronized void registerPool(String name, ObjectPool pool) {
  126. _pools.put(name,pool);
  127. }
  128. public synchronized void closePool(String name) throws SQLException {
  129. ObjectPool pool = (ObjectPool) _pools.get(name);
  130. if (pool != null) {
  131. _pools.remove(name);
  132. try {
  133. pool.close();
  134. }
  135. catch (Exception e) {
  136. throw new SQLNestedException("Error closing pool " + name, e);
  137. }
  138. }
  139. }
  140. public synchronized String[] getPoolNames() throws SQLException{
  141. Set names = _pools.keySet();
  142. return (String[]) names.toArray(new String[names.size()]);
  143. }
  144. public boolean acceptsURL(String url) throws SQLException {
  145. try {
  146. return url.startsWith(URL_PREFIX);
  147. } catch(NullPointerException e) {
  148. return false;
  149. }
  150. }
  151. public Connection connect(String url, Properties info) throws SQLException {
  152. if(acceptsURL(url)) {
  153. ObjectPool pool = getConnectionPool(url.substring(URL_PREFIX_LEN));
  154. if(null == pool) {
  155. throw new SQLException("No pool found for " + url + ".");
  156. } else {
  157. try {
  158. Connection conn = (Connection)(pool.borrowObject());
  159. if (conn != null) {
  160. conn = new PoolGuardConnectionWrapper(conn);
  161. }
  162. return conn;
  163. } catch(SQLException e) {
  164. throw e;
  165. } catch(NoSuchElementException e) {
  166. throw new SQLNestedException("Cannot get a connection, pool exhausted", e);
  167. } catch(RuntimeException e) {
  168. throw e;
  169. } catch(Exception e) {
  170. throw new SQLNestedException("Cannot get a connection, general error", e);
  171. }
  172. }
  173. } else {
  174. return null;
  175. }
  176. }
  177. public int getMajorVersion() {
  178. return MAJOR_VERSION;
  179. }
  180. public int getMinorVersion() {
  181. return MINOR_VERSION;
  182. }
  183. public boolean jdbcCompliant() {
  184. return true;
  185. }
  186. public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) {
  187. return new DriverPropertyInfo[0];
  188. }
  189. /** My URL prefix */
  190. protected static String URL_PREFIX = "jdbc:apache:commons:dbcp:";
  191. protected static int URL_PREFIX_LEN = URL_PREFIX.length();
  192. // version numbers
  193. protected static int MAJOR_VERSION = 1;
  194. protected static int MINOR_VERSION = 0;
  195. /**
  196. * PoolGuardConnectionWrapper is a Connection wrapper that makes sure a
  197. * closed connection cannot be used anymore.
  198. */
  199. private class PoolGuardConnectionWrapper extends DelegatingConnection {
  200. private Connection delegate;
  201. PoolGuardConnectionWrapper(Connection delegate) {
  202. super(delegate);
  203. this.delegate = delegate;
  204. }
  205. protected void checkOpen() throws SQLException {
  206. if(delegate == null) {
  207. throw new SQLException("Connection is closed.");
  208. }
  209. }
  210. public void close() throws SQLException {
  211. checkOpen();
  212. this.delegate.close();
  213. this.delegate = null;
  214. super.setDelegate(null);
  215. }
  216. public boolean isClosed() throws SQLException {
  217. if (delegate == null) {
  218. return true;
  219. }
  220. return delegate.isClosed();
  221. }
  222. public void clearWarnings() throws SQLException {
  223. checkOpen();
  224. delegate.clearWarnings();
  225. }
  226. public void commit() throws SQLException {
  227. checkOpen();
  228. delegate.commit();
  229. }
  230. public Statement createStatement() throws SQLException {
  231. checkOpen();
  232. return delegate.createStatement();
  233. }
  234. public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
  235. checkOpen();
  236. return delegate.createStatement(resultSetType, resultSetConcurrency);
  237. }
  238. public boolean equals(Object obj) {
  239. if (delegate == null){
  240. return false;
  241. }
  242. return delegate.equals(obj);
  243. }
  244. public boolean getAutoCommit() throws SQLException {
  245. checkOpen();
  246. return delegate.getAutoCommit();
  247. }
  248. public String getCatalog() throws SQLException {
  249. checkOpen();
  250. return delegate.getCatalog();
  251. }
  252. public DatabaseMetaData getMetaData() throws SQLException {
  253. checkOpen();
  254. return delegate.getMetaData();
  255. }
  256. public int getTransactionIsolation() throws SQLException {
  257. checkOpen();
  258. return delegate.getTransactionIsolation();
  259. }
  260. public Map getTypeMap() throws SQLException {
  261. checkOpen();
  262. return delegate.getTypeMap();
  263. }
  264. public SQLWarning getWarnings() throws SQLException {
  265. checkOpen();
  266. return delegate.getWarnings();
  267. }
  268. public int hashCode() {
  269. if (delegate == null){
  270. return 0;
  271. }
  272. return delegate.hashCode();
  273. }
  274. public boolean isReadOnly() throws SQLException {
  275. checkOpen();
  276. return delegate.isReadOnly();
  277. }
  278. public String nativeSQL(String sql) throws SQLException {
  279. checkOpen();
  280. return delegate.nativeSQL(sql);
  281. }
  282. public CallableStatement prepareCall(String sql) throws SQLException {
  283. checkOpen();
  284. return delegate.prepareCall(sql);
  285. }
  286. public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
  287. checkOpen();
  288. return delegate.prepareCall(sql, resultSetType, resultSetConcurrency);
  289. }
  290. public PreparedStatement prepareStatement(String sql) throws SQLException {
  291. checkOpen();
  292. return delegate.prepareStatement(sql);
  293. }
  294. public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
  295. checkOpen();
  296. return delegate.prepareStatement(sql, resultSetType, resultSetConcurrency);
  297. }
  298. public void rollback() throws SQLException {
  299. checkOpen();
  300. delegate.rollback();
  301. }
  302. public void setAutoCommit(boolean autoCommit) throws SQLException {
  303. checkOpen();
  304. delegate.setAutoCommit(autoCommit);
  305. }
  306. public void setCatalog(String catalog) throws SQLException {
  307. checkOpen();
  308. delegate.setCatalog(catalog);
  309. }
  310. public void setReadOnly(boolean readOnly) throws SQLException {
  311. checkOpen();
  312. delegate.setReadOnly(readOnly);
  313. }
  314. public void setTransactionIsolation(int level) throws SQLException {
  315. checkOpen();
  316. delegate.setTransactionIsolation(level);
  317. }
  318. public void setTypeMap(Map map) throws SQLException {
  319. checkOpen();
  320. delegate.setTypeMap(map);
  321. }
  322. public String toString() {
  323. if (delegate == null){
  324. return null;
  325. }
  326. return delegate.toString();
  327. }
  328. // ------------------- JDBC 3.0 -----------------------------------------
  329. // Will be commented by the build process on a JDBC 2.0 system
  330. /* JDBC_3_ANT_KEY_BEGIN */
  331. public int getHoldability() throws SQLException {
  332. checkOpen();
  333. return delegate.getHoldability();
  334. }
  335. public void setHoldability(int holdability) throws SQLException {
  336. checkOpen();
  337. delegate.setHoldability(holdability);
  338. }
  339. public java.sql.Savepoint setSavepoint() throws SQLException {
  340. checkOpen();
  341. return delegate.setSavepoint();
  342. }
  343. public java.sql.Savepoint setSavepoint(String name) throws SQLException {
  344. checkOpen();
  345. return delegate.setSavepoint(name);
  346. }
  347. public void releaseSavepoint(java.sql.Savepoint savepoint) throws SQLException {
  348. checkOpen();
  349. delegate.releaseSavepoint(savepoint);
  350. }
  351. public void rollback(java.sql.Savepoint savepoint) throws SQLException {
  352. checkOpen();
  353. delegate.rollback(savepoint);
  354. }
  355. public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
  356. checkOpen();
  357. return delegate.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
  358. }
  359. public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
  360. checkOpen();
  361. return delegate.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
  362. }
  363. public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
  364. checkOpen();
  365. return delegate.prepareStatement(sql, autoGeneratedKeys);
  366. }
  367. public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
  368. checkOpen();
  369. return delegate.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
  370. }
  371. public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
  372. checkOpen();
  373. return delegate.prepareStatement(sql, columnIndexes);
  374. }
  375. public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
  376. checkOpen();
  377. return delegate.prepareStatement(sql, columnNames);
  378. }
  379. /* JDBC_3_ANT_KEY_END */
  380. /**
  381. * @see org.apache.commons.dbcp.DelegatingConnection#getDelegate()
  382. */
  383. public Connection getDelegate() {
  384. if (isAccessToUnderlyingConnectionAllowed()) {
  385. return super.getDelegate();
  386. } else {
  387. return null;
  388. }
  389. }
  390. /**
  391. * @see org.apache.commons.dbcp.DelegatingConnection#getInnermostDelegate()
  392. */
  393. public Connection getInnermostDelegate() {
  394. if (isAccessToUnderlyingConnectionAllowed()) {
  395. return super.getInnermostDelegate();
  396. } else {
  397. return null;
  398. }
  399. }
  400. }
  401. }