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.datasources;
  17. import java.io.IOException;
  18. import java.io.ObjectInputStream;
  19. import java.sql.Connection;
  20. import java.sql.SQLException;
  21. import java.util.Map;
  22. import javax.naming.NamingException;
  23. import javax.sql.ConnectionPoolDataSource;
  24. import org.apache.commons.collections.LRUMap;
  25. import org.apache.commons.pool.KeyedObjectPool;
  26. import org.apache.commons.pool.impl.GenericKeyedObjectPool;
  27. import org.apache.commons.pool.impl.GenericObjectPool;
  28. import org.apache.commons.dbcp.SQLNestedException;
  29. /**
  30. * A pooling <code>DataSource</code> appropriate for deployment within
  31. * J2EE environment. There are many configuration options, most of which are
  32. * defined in the parent class. All users (based on username) share a single
  33. * maximum number of Connections in this datasource.
  34. *
  35. * @author John D. McNally
  36. * @version $Revision: 1.9 $ $Date: 2004/02/28 12:18:17 $
  37. */
  38. public class SharedPoolDataSource
  39. extends InstanceKeyDataSource {
  40. private static final Map userKeys = new LRUMap(10);
  41. private int maxActive = GenericObjectPool.DEFAULT_MAX_ACTIVE;
  42. private int maxIdle = GenericObjectPool.DEFAULT_MAX_IDLE;
  43. private int maxWait = (int)Math.min((long)Integer.MAX_VALUE,
  44. GenericObjectPool.DEFAULT_MAX_WAIT);
  45. private KeyedObjectPool pool = null;
  46. /**
  47. * Default no-arg constructor for Serialization
  48. */
  49. public SharedPoolDataSource() {
  50. }
  51. /**
  52. * Close pool being maintained by this datasource.
  53. */
  54. public void close() throws Exception {
  55. pool.close();
  56. InstanceKeyObjectFactory.removeInstance(instanceKey);
  57. }
  58. // -------------------------------------------------------------------
  59. // Properties
  60. /**
  61. * The maximum number of active connections that can be allocated from
  62. * this pool at the same time, or zero for no limit.
  63. * The default is 0.
  64. */
  65. public int getMaxActive() {
  66. return (this.maxActive);
  67. }
  68. /**
  69. * The maximum number of active connections that can be allocated from
  70. * this pool at the same time, or zero for no limit.
  71. * The default is 0.
  72. */
  73. public void setMaxActive(int maxActive) {
  74. assertInitializationAllowed();
  75. this.maxActive = maxActive;
  76. }
  77. /**
  78. * The maximum number of active connections that can remain idle in the
  79. * pool, without extra ones being released, or zero for no limit.
  80. * The default is 0.
  81. */
  82. public int getMaxIdle() {
  83. return (this.maxIdle);
  84. }
  85. /**
  86. * The maximum number of active connections that can remain idle in the
  87. * pool, without extra ones being released, or zero for no limit.
  88. * The default is 0.
  89. */
  90. public void setMaxIdle(int maxIdle) {
  91. assertInitializationAllowed();
  92. this.maxIdle = maxIdle;
  93. }
  94. /**
  95. * The maximum number of milliseconds that the pool will wait (when there
  96. * are no available connections) for a connection to be returned before
  97. * throwing an exception, or -1 to wait indefinitely. Will fail
  98. * immediately if value is 0.
  99. * The default is -1.
  100. */
  101. public int getMaxWait() {
  102. return (this.maxWait);
  103. }
  104. /**
  105. * The maximum number of milliseconds that the pool will wait (when there
  106. * are no available connections) for a connection to be returned before
  107. * throwing an exception, or -1 to wait indefinitely. Will fail
  108. * immediately if value is 0.
  109. * The default is -1.
  110. */
  111. public void setMaxWait(int maxWait) {
  112. assertInitializationAllowed();
  113. this.maxWait = maxWait;
  114. }
  115. // ----------------------------------------------------------------------
  116. // Instrumentation Methods
  117. /**
  118. * Get the number of active connections in the pool.
  119. */
  120. public int getNumActive() {
  121. return (pool == null) ? 0 : pool.getNumActive();
  122. }
  123. /**
  124. * Get the number of idle connections in the pool.
  125. */
  126. public int getNumIdle() {
  127. return (pool == null) ? 0 : pool.getNumIdle();
  128. }
  129. // ----------------------------------------------------------------------
  130. // Inherited abstract methods
  131. protected synchronized PooledConnectionAndInfo
  132. getPooledConnectionAndInfo(String username, String password)
  133. throws SQLException {
  134. if (pool == null) {
  135. try {
  136. registerPool(username, password);
  137. } catch (NamingException e) {
  138. throw new SQLNestedException("RegisterPool failed", e);
  139. }
  140. }
  141. PooledConnectionAndInfo info = null;
  142. try {
  143. info = (PooledConnectionAndInfo) pool
  144. .borrowObject(getUserPassKey(username, password));
  145. }
  146. catch (Exception e) {
  147. throw new SQLNestedException(
  148. "Could not retrieve connection info from pool", e);
  149. }
  150. return info;
  151. }
  152. private UserPassKey getUserPassKey(String username, String password) {
  153. UserPassKey key = (UserPassKey) userKeys.get(username);
  154. if (key == null) {
  155. key = new UserPassKey(username, password);
  156. userKeys.put(username, key);
  157. }
  158. return key;
  159. }
  160. private void registerPool(
  161. String username, String password)
  162. throws javax.naming.NamingException, SQLException {
  163. ConnectionPoolDataSource cpds = testCPDS(username, password);
  164. // Create an object pool to contain our PooledConnections
  165. GenericKeyedObjectPool tmpPool = new GenericKeyedObjectPool(null);
  166. tmpPool.setMaxActive(getMaxActive());
  167. tmpPool.setMaxIdle(getMaxIdle());
  168. tmpPool.setMaxWait(getMaxWait());
  169. tmpPool.setWhenExhaustedAction(whenExhaustedAction(maxActive, maxWait));
  170. tmpPool.setTestOnBorrow(getTestOnBorrow());
  171. tmpPool.setTestOnReturn(getTestOnReturn());
  172. tmpPool.setTimeBetweenEvictionRunsMillis(
  173. getTimeBetweenEvictionRunsMillis());
  174. tmpPool.setNumTestsPerEvictionRun(getNumTestsPerEvictionRun());
  175. tmpPool.setMinEvictableIdleTimeMillis(getMinEvictableIdleTimeMillis());
  176. tmpPool.setTestWhileIdle(getTestWhileIdle());
  177. pool = tmpPool;
  178. // Set up the factory we will use (passing the pool associates
  179. // the factory with the pool, so we do not have to do so
  180. // explicitly)
  181. new KeyedCPDSConnectionFactory(cpds, pool, getValidationQuery());
  182. }
  183. protected void setupDefaults(Connection con, String username)
  184. throws SQLException {
  185. con.setAutoCommit(isDefaultAutoCommit());
  186. con.setReadOnly(isDefaultReadOnly());
  187. int defaultTransactionIsolation = getDefaultTransactionIsolation();
  188. if (defaultTransactionIsolation != UNKNOWN_TRANSACTIONISOLATION) {
  189. con.setTransactionIsolation(defaultTransactionIsolation);
  190. }
  191. }
  192. /**
  193. * Supports Serialization interface.
  194. *
  195. * @param in a <code>java.io.ObjectInputStream</code> value
  196. * @exception IOException if an error occurs
  197. * @exception ClassNotFoundException if an error occurs
  198. */
  199. private void readObject(ObjectInputStream in)
  200. throws IOException, ClassNotFoundException {
  201. try
  202. {
  203. in.defaultReadObject();
  204. SharedPoolDataSource oldDS = (SharedPoolDataSource)
  205. new SharedPoolDataSourceFactory()
  206. .getObjectInstance(getReference(), null, null, null);
  207. this.pool = oldDS.pool;
  208. }
  209. catch (NamingException e)
  210. {
  211. throw new IOException("NamingException: " + e);
  212. }
  213. }
  214. }