001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/db/tags/sakai_2-4-1/db-impl/ext/src/java/org/apache/commons/dbcp/SakaiBasicDataSource.java $
003: * $Id: SakaiBasicDataSource.java 9718 2006-05-20 00:19:01Z ggolden@umich.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2005, 2006 The Sakai Foundation.
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.apache.commons.dbcp;
021:
022: import java.sql.Connection;
023: import java.sql.Driver;
024: import java.sql.DriverManager;
025: import java.sql.SQLException;
026:
027: import javax.sql.DataSource;
028:
029: import org.apache.commons.logging.Log;
030: import org.apache.commons.logging.LogFactory;
031: import org.apache.commons.pool.impl.GenericKeyedObjectPool;
032: import org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory;
033: import org.apache.commons.pool.impl.GenericObjectPool;
034:
035: /**
036: * <p>
037: * SakaiBasicDataSource extends apache common's BasicDataSource ...
038: * </p>
039: */
040: public class SakaiBasicDataSource extends BasicDataSource {
041: /** Our logger. */
042: private static Log M_log = LogFactory
043: .getLog(SakaiBasicDataSource.class);
044:
045: /** Configuration: to rollback each connection when returned to the pool. */
046: protected boolean m_rollbackOnReturn = false;
047:
048: /**
049: * Set the default transaction isolation level from a string value, based on the settings and values in java.sql.Connection
050: *
051: * @param defaultTransactionIsolation
052: */
053: public void setDefaultTransactionIsolationString(
054: String defaultTransactionIsolation) {
055: if ((defaultTransactionIsolation == null)
056: || (defaultTransactionIsolation.trim().length() == 0)) {
057: setDefaultTransactionIsolation(PoolableConnectionFactory.UNKNOWN_TRANSACTIONISOLATION);
058: } else if (defaultTransactionIsolation.trim().equalsIgnoreCase(
059: "TRANSACTION_NONE")) {
060: setDefaultTransactionIsolation(Connection.TRANSACTION_NONE);
061: } else if (defaultTransactionIsolation.trim().equalsIgnoreCase(
062: "TRANSACTION_READ_UNCOMMITTED")) {
063: setDefaultTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
064: } else if (defaultTransactionIsolation.trim().equalsIgnoreCase(
065: "TRANSACTION_READ_COMMITTED")) {
066: setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
067: } else if (defaultTransactionIsolation.trim().equalsIgnoreCase(
068: "TRANSACTION_REPEATABLE_READ")) {
069: setDefaultTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
070: } else if (defaultTransactionIsolation.trim().equalsIgnoreCase(
071: "TRANSACTION_SERIALIZABLE")) {
072: setDefaultTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
073: } else {
074: setDefaultTransactionIsolation(PoolableConnectionFactory.UNKNOWN_TRANSACTIONISOLATION);
075: M_log.warn("invalid transaction isolation level: "
076: + defaultTransactionIsolation);
077: }
078: }
079:
080: /**
081: * Set the rollback on borrow configuration.
082: *
083: * @param value
084: * if true, rollback each connection when borrowed from the pool, if false, do not.
085: */
086: public void setRollbackOnBorrow(boolean value) {
087: m_rollbackOnReturn = value;
088: }
089:
090: /**
091: * <p>
092: * Sakai changes: use the SakaiPoolableConnectionFactory, removed some not-visible (damn the use of private!) code.
093: * </p>
094: * <p>
095: * Create (if necessary) and return the internal data source we are using to manage our connections.
096: * </p>
097: * <p>
098: * <strong>IMPLEMENTATION NOTE</strong> - It is tempting to use the "double checked locking" idiom in an attempt to avoid synchronizing on every single call to this method. However, this idiom fails to work correctly in the face of some optimizations
099: * that are legal for a JVM to perform.
100: * </p>
101: *
102: * @exception SQLException
103: * if the object pool cannot be created.
104: */
105: protected synchronized DataSource createDataSource()
106: throws SQLException {
107:
108: // Return the pool if we have already created it
109: if (dataSource != null) {
110: return (dataSource);
111: }
112:
113: // Load the JDBC driver class
114: if (driverClassName != null) {
115: try {
116: Class.forName(driverClassName);
117: } catch (Throwable t) {
118: String message = "Cannot load JDBC driver class '"
119: + driverClassName + "'";
120: logWriter.println(message);
121: t.printStackTrace(logWriter);
122: throw new SQLNestedException(message, t);
123: }
124: }
125:
126: // Create a JDBC driver instance
127: Driver driver = null;
128: try {
129: driver = DriverManager.getDriver(url);
130: } catch (Throwable t) {
131: String message = "Cannot create JDBC driver of class '"
132: + (driverClassName != null ? driverClassName : "")
133: + "' for connect URL '" + url + "'";
134: logWriter.println(message);
135: t.printStackTrace(logWriter);
136: throw new SQLNestedException(message, t);
137: }
138:
139: // Can't test without a validationQuery
140: if (validationQuery == null) {
141: setTestOnBorrow(false);
142: setTestOnReturn(false);
143: setTestWhileIdle(false);
144: }
145:
146: // Create an object pool to contain our active connections
147: // Sakai:
148: // if ((abandonedConfig != null) && (abandonedConfig.getRemoveAbandoned() == true))
149: // {
150: // connectionPool = new AbandonedObjectPool(null, abandonedConfig);
151: // }
152: // else
153: {
154: connectionPool = new GenericObjectPool();
155: }
156: connectionPool.setMaxActive(maxActive);
157: connectionPool.setMaxIdle(maxIdle);
158: connectionPool.setMinIdle(minIdle);
159: connectionPool.setMaxWait(maxWait);
160: connectionPool.setTestOnBorrow(testOnBorrow);
161: connectionPool.setTestOnReturn(testOnReturn);
162: connectionPool
163: .setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
164: connectionPool
165: .setNumTestsPerEvictionRun(numTestsPerEvictionRun);
166: connectionPool
167: .setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
168: connectionPool.setTestWhileIdle(testWhileIdle);
169:
170: // Set up statement pool, if desired
171: GenericKeyedObjectPoolFactory statementPoolFactory = null;
172: if (isPoolPreparedStatements()) {
173: statementPoolFactory = new GenericKeyedObjectPoolFactory(
174: null, -1, // unlimited maxActive (per key)
175: GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL, 0, // maxWait
176: 1, // maxIdle (per key)
177: maxOpenPreparedStatements);
178: }
179:
180: // Set up the driver connection factory we will use
181: if (username != null) {
182: connectionProperties.put("user", username);
183: } else {
184: // Sakai: log("DBCP DataSource configured without a 'username'");
185: }
186:
187: if (password != null) {
188: connectionProperties.put("password", password);
189: } else {
190: // Sakai: log("DBCP DataSource configured without a 'password'");
191: }
192:
193: DriverConnectionFactory driverConnectionFactory = new DriverConnectionFactory(
194: driver, url, connectionProperties);
195:
196: // Set up the poolable connection factory we will use
197: PoolableConnectionFactory connectionFactory = null;
198: try {
199: connectionFactory = new SakaiPoolableConnectionFactory(
200: driverConnectionFactory, connectionPool,
201: statementPoolFactory, validationQuery,
202: defaultReadOnly, defaultAutoCommit,
203: defaultTransactionIsolation, defaultCatalog,
204: /* abandonedConfig Sakai: */null,
205: m_rollbackOnReturn);
206: if (connectionFactory == null) {
207: throw new SQLException(
208: "Cannot create PoolableConnectionFactory");
209: }
210: // Sakai: validateConnectionFactory(connectionFactory);
211: } catch (RuntimeException e) {
212: throw e;
213: } catch (Exception e) {
214: throw new SQLNestedException(
215: "Cannot create PoolableConnectionFactory ("
216: + e.getMessage() + ")", e);
217: }
218:
219: // Create and return the pooling data source to manage the connections
220: dataSource = new PoolingDataSource(connectionPool);
221: ((PoolingDataSource) dataSource)
222: .setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
223: dataSource.setLogWriter(logWriter);
224:
225: try {
226: for (int i = 0; i < initialSize; i++) {
227: connectionPool.addObject();
228: }
229: } catch (Exception e) {
230: throw new SQLNestedException(
231: "Error preloading the connection pool", e);
232: }
233:
234: return dataSource;
235: }
236: }
|