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.ByteArrayInputStream;
  18. import java.sql.Connection;
  19. import java.util.Enumeration;
  20. import java.util.Hashtable;
  21. import java.util.Properties;
  22. import javax.naming.Context;
  23. import javax.naming.Name;
  24. import javax.naming.RefAddr;
  25. import javax.naming.Reference;
  26. import javax.naming.spi.ObjectFactory;
  27. import javax.sql.DataSource;
  28. /**
  29. * <p>JNDI object factory that creates an instance of
  30. * <code>BasicDataSource</code> that has been configured based on the
  31. * <code>RefAddr</code> values of the specified <code>Reference</code>,
  32. * which must match the names and data types of the
  33. * <code>BasicDataSource</code> bean properties.</p>
  34. *
  35. * @author Craig R. McClanahan
  36. * @author Dirk Verbeeck
  37. * @version $Revision: 1.15 $ $Date: 2004/02/28 11:48:04 $
  38. */
  39. public class BasicDataSourceFactory implements ObjectFactory {
  40. private final static String PROP_DEFAULTAUTOCOMMIT = "defaultAutoCommit";
  41. private final static String PROP_DEFAULTREADONLY = "defaultReadOnly";
  42. private final static String PROP_DEFAULTTRANSACTIONISOLATION = "defaultTransactionIsolation";
  43. private final static String PROP_DEFAULTCATALOG = "defaultCatalog";
  44. private final static String PROP_DRIVERCLASSNAME = "driverClassName";
  45. private final static String PROP_MAXACTIVE = "maxActive";
  46. private final static String PROP_MAXIDLE = "maxIdle";
  47. private final static String PROP_MINIDLE = "minIdle";
  48. private final static String PROP_INITIALSIZE = "initialSize";
  49. private final static String PROP_MAXWAIT = "maxWait";
  50. private final static String PROP_TESTONBORROW = "testOnBorrow";
  51. private final static String PROP_TESTONRETURN = "testOnReturn";
  52. private final static String PROP_TIMEBETWEENEVICTIONRUNSMILLIS = "timeBetweenEvictionRunsMillis";
  53. private final static String PROP_NUMTESTSPEREVICTIONRUN = "numTestsPerEvictionRun";
  54. private final static String PROP_MINEVICTABLEIDLETIMEMILLIS = "minEvictableIdleTimeMillis";
  55. private final static String PROP_TESTWHILEIDLE = "testWhileIdle";
  56. private final static String PROP_PASSWORD = "password";
  57. private final static String PROP_URL = "url";
  58. private final static String PROP_USERNAME = "username";
  59. private final static String PROP_VALIDATIONQUERY = "validationQuery";
  60. private final static String PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED = "accessToUnderlyingConnectionAllowed";
  61. private final static String PROP_REMOVEABANDONED = "removeAbandoned";
  62. private final static String PROP_REMOVEABANDONEDTIMEOUT = "removeAbandonedTimeout";
  63. private final static String PROP_LOGABANDONED = "logAbandoned";
  64. private final static String PROP_POOLPREPAREDSTATEMENTS = "poolPreparedStatements";
  65. private final static String PROP_MAXOPENPREPAREDSTATEMENTS = "maxOpenPreparedStatements";
  66. private final static String PROP_CONNECTIONPROPERTIES = "connectionProperties";
  67. private final static String[] ALL_PROPERTIES = {
  68. PROP_DEFAULTAUTOCOMMIT,
  69. PROP_DEFAULTREADONLY,
  70. PROP_DEFAULTTRANSACTIONISOLATION,
  71. PROP_DEFAULTCATALOG,
  72. PROP_DRIVERCLASSNAME,
  73. PROP_MAXACTIVE,
  74. PROP_MAXIDLE,
  75. PROP_MINIDLE,
  76. PROP_INITIALSIZE,
  77. PROP_MAXWAIT,
  78. PROP_TESTONBORROW,
  79. PROP_TESTONRETURN,
  80. PROP_TIMEBETWEENEVICTIONRUNSMILLIS,
  81. PROP_NUMTESTSPEREVICTIONRUN,
  82. PROP_MINEVICTABLEIDLETIMEMILLIS,
  83. PROP_TESTWHILEIDLE,
  84. PROP_PASSWORD,
  85. PROP_URL,
  86. PROP_USERNAME,
  87. PROP_VALIDATIONQUERY,
  88. PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED,
  89. PROP_REMOVEABANDONED,
  90. PROP_REMOVEABANDONEDTIMEOUT,
  91. PROP_LOGABANDONED,
  92. PROP_POOLPREPAREDSTATEMENTS,
  93. PROP_MAXOPENPREPAREDSTATEMENTS,
  94. PROP_CONNECTIONPROPERTIES
  95. };
  96. // -------------------------------------------------- ObjectFactory Methods
  97. /**
  98. * <p>Create and return a new <code>BasicDataSource</code> instance. If no
  99. * instance can be created, return <code>null</code> instead.</p>
  100. *
  101. * @param obj The possibly null object containing location or
  102. * reference information that can be used in creating an object
  103. * @param name The name of this object relative to <code>nameCtx</code>
  104. * @param nameCts The context relative to which the <code>name</code>
  105. * parameter is specified, or <code>null</code> if <code>name</code>
  106. * is relative to the default initial context
  107. * @param environment The possibly null environment that is used in
  108. * creating this object
  109. *
  110. * @exception Exception if an exception occurs creating the instance
  111. */
  112. public Object getObjectInstance(Object obj, Name name, Context nameCtx,
  113. Hashtable environment)
  114. throws Exception {
  115. // We only know how to deal with <code>javax.naming.Reference</code>s
  116. // that specify a class name of "javax.sql.DataSource"
  117. if ((obj == null) || !(obj instanceof Reference)) {
  118. return null;
  119. }
  120. Reference ref = (Reference) obj;
  121. if (!"javax.sql.DataSource".equals(ref.getClassName())) {
  122. return null;
  123. }
  124. Properties properties = new Properties();
  125. for (int i = 0 ; i < ALL_PROPERTIES.length ; i++) {
  126. String propertyName = ALL_PROPERTIES[i];
  127. RefAddr ra = ref.get(propertyName);
  128. if (ra != null) {
  129. String propertyValue = ra.getContent().toString();
  130. properties.setProperty(propertyName, propertyValue);
  131. }
  132. }
  133. return createDataSource(properties);
  134. }
  135. /**
  136. * Creates and configures a BasicDataSource instance based on the
  137. * given properties.
  138. */
  139. public static DataSource createDataSource(Properties properties) throws Exception {
  140. BasicDataSource dataSource = new BasicDataSource();
  141. String value = null;
  142. value = properties.getProperty(PROP_DEFAULTAUTOCOMMIT);
  143. if (value != null) {
  144. dataSource.setDefaultAutoCommit(Boolean.valueOf(value).booleanValue());
  145. }
  146. value = properties.getProperty(PROP_DEFAULTREADONLY);
  147. if (value != null) {
  148. dataSource.setDefaultReadOnly(Boolean.valueOf(value).booleanValue());
  149. }
  150. value = properties.getProperty(PROP_DEFAULTTRANSACTIONISOLATION);
  151. if (value != null) {
  152. int level = PoolableConnectionFactory.UNKNOWN_TRANSACTIONISOLATION;
  153. if ("NONE".equalsIgnoreCase(value)) {
  154. level = Connection.TRANSACTION_NONE;
  155. }
  156. else if ("READ_COMMITTED".equalsIgnoreCase(value)) {
  157. level = Connection.TRANSACTION_READ_COMMITTED;
  158. }
  159. else if ("READ_UNCOMMITTED".equalsIgnoreCase(value)) {
  160. level = Connection.TRANSACTION_READ_UNCOMMITTED;
  161. }
  162. else if ("REPEATABLE_READ".equalsIgnoreCase(value)) {
  163. level = Connection.TRANSACTION_REPEATABLE_READ;
  164. }
  165. else if ("SERIALIZABLE".equalsIgnoreCase(value)) {
  166. level = Connection.TRANSACTION_SERIALIZABLE;
  167. }
  168. else {
  169. try {
  170. level = Integer.parseInt(value);
  171. } catch (NumberFormatException e) {
  172. System.err.println("Could not parse defaultTransactionIsolation: " + value);
  173. System.err.println("WARNING: defaultTransactionIsolation not set");
  174. System.err.println("using default value of database driver");
  175. level = PoolableConnectionFactory.UNKNOWN_TRANSACTIONISOLATION;
  176. }
  177. }
  178. dataSource.setDefaultTransactionIsolation(level);
  179. }
  180. value = properties.getProperty(PROP_DEFAULTCATALOG);
  181. if (value != null) {
  182. dataSource.setDefaultCatalog(value);
  183. }
  184. value = properties.getProperty(PROP_DRIVERCLASSNAME);
  185. if (value != null) {
  186. dataSource.setDriverClassName(value);
  187. }
  188. value = properties.getProperty(PROP_MAXACTIVE);
  189. if (value != null) {
  190. dataSource.setMaxActive(Integer.parseInt(value));
  191. }
  192. value = properties.getProperty(PROP_MAXIDLE);
  193. if (value != null) {
  194. dataSource.setMaxIdle(Integer.parseInt(value));
  195. }
  196. value = properties.getProperty(PROP_MINIDLE);
  197. if (value != null) {
  198. dataSource.setMinIdle(Integer.parseInt(value));
  199. }
  200. value = properties.getProperty(PROP_INITIALSIZE);
  201. if (value != null) {
  202. dataSource.setInitialSize(Integer.parseInt(value));
  203. }
  204. value = properties.getProperty(PROP_MAXWAIT);
  205. if (value != null) {
  206. dataSource.setMaxWait(Long.parseLong(value));
  207. }
  208. value = properties.getProperty(PROP_TESTONBORROW);
  209. if (value != null) {
  210. dataSource.setTestOnBorrow(Boolean.valueOf(value).booleanValue());
  211. }
  212. value = properties.getProperty(PROP_TESTONRETURN);
  213. if (value != null) {
  214. dataSource.setTestOnReturn(Boolean.valueOf(value).booleanValue());
  215. }
  216. value = properties.getProperty(PROP_TIMEBETWEENEVICTIONRUNSMILLIS);
  217. if (value != null) {
  218. dataSource.setTimeBetweenEvictionRunsMillis(Long.parseLong(value));
  219. }
  220. value = properties.getProperty(PROP_NUMTESTSPEREVICTIONRUN);
  221. if (value != null) {
  222. dataSource.setNumTestsPerEvictionRun(Integer.parseInt(value));
  223. }
  224. value = properties.getProperty(PROP_MINEVICTABLEIDLETIMEMILLIS);
  225. if (value != null) {
  226. dataSource.setMinEvictableIdleTimeMillis(Long.parseLong(value));
  227. }
  228. value = properties.getProperty(PROP_TESTWHILEIDLE);
  229. if (value != null) {
  230. dataSource.setTestWhileIdle(Boolean.valueOf(value).booleanValue());
  231. }
  232. value = properties.getProperty(PROP_PASSWORD);
  233. if (value != null) {
  234. dataSource.setPassword(value);
  235. }
  236. value = properties.getProperty(PROP_URL);
  237. if (value != null) {
  238. dataSource.setUrl(value);
  239. }
  240. value = properties.getProperty(PROP_USERNAME);
  241. if (value != null) {
  242. dataSource.setUsername(value);
  243. }
  244. value = properties.getProperty(PROP_VALIDATIONQUERY);
  245. if (value != null) {
  246. dataSource.setValidationQuery(value);
  247. }
  248. value = properties.getProperty(PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED);
  249. if (value != null) {
  250. dataSource.setAccessToUnderlyingConnectionAllowed(Boolean.valueOf(value).booleanValue());
  251. }
  252. value = properties.getProperty(PROP_REMOVEABANDONED);
  253. if (value != null) {
  254. dataSource.setRemoveAbandoned(Boolean.valueOf(value).booleanValue());
  255. }
  256. value = properties.getProperty(PROP_REMOVEABANDONEDTIMEOUT);
  257. if (value != null) {
  258. dataSource.setRemoveAbandonedTimeout(Integer.parseInt(value));
  259. }
  260. value = properties.getProperty(PROP_LOGABANDONED);
  261. if (value != null) {
  262. dataSource.setLogAbandoned(Boolean.valueOf(value).booleanValue());
  263. }
  264. value = properties.getProperty(PROP_POOLPREPAREDSTATEMENTS);
  265. if (value != null) {
  266. dataSource.setPoolPreparedStatements(Boolean.valueOf(value).booleanValue());
  267. }
  268. value = properties.getProperty(PROP_MAXOPENPREPAREDSTATEMENTS);
  269. if (value != null) {
  270. dataSource.setMaxOpenPreparedStatements(Integer.parseInt(value));
  271. }
  272. value = properties.getProperty(PROP_CONNECTIONPROPERTIES);
  273. if (value != null) {
  274. Properties p = getProperties(value);
  275. Enumeration e = p.propertyNames();
  276. while (e.hasMoreElements()) {
  277. String propertyName = (String) e.nextElement();
  278. dataSource.addConnectionProperty(propertyName, p.getProperty(propertyName));
  279. }
  280. }
  281. // Return the configured DataSource instance
  282. return dataSource;
  283. }
  284. /**
  285. * <p>Parse properties from the string. Format of the string must be [propertyName=property;]*<p>
  286. * @param propText
  287. * @return Properties
  288. * @throws Exception
  289. */
  290. static private Properties getProperties(String propText) throws Exception {
  291. Properties p = new Properties();
  292. if (propText != null) {
  293. p.load(new ByteArrayInputStream(propText.replace(';', '\n').getBytes()));
  294. }
  295. return p;
  296. }
  297. }