001: //$Id: C3P0ConnectionProvider.java 11067 2007-01-19 15:14:43Z steve.ebersole@jboss.com $
002: package org.hibernate.connection;
003:
004: import java.sql.Connection;
005: import java.sql.SQLException;
006: import java.util.Iterator;
007: import java.util.Properties;
008:
009: import javax.sql.DataSource;
010:
011: import org.apache.commons.logging.Log;
012: import org.apache.commons.logging.LogFactory;
013:
014: import com.mchange.v2.c3p0.DataSources;
015:
016: import org.hibernate.HibernateException;
017: import org.hibernate.cfg.Environment;
018: import org.hibernate.util.PropertiesHelper;
019: import org.hibernate.util.ReflectHelper;
020:
021: /**
022: * A connection provider that uses a C3P0 connection pool. Hibernate will use this by
023: * default if the <tt>hibernate.c3p0.*</tt> properties are set.
024: *
025: * @author various people
026: * @see ConnectionProvider
027: */
028: public class C3P0ConnectionProvider implements ConnectionProvider {
029:
030: private static final Log log = LogFactory
031: .getLog(C3P0ConnectionProvider.class);
032:
033: //swaldman 2006-08-28: define c3p0-style configuration parameters for properties with
034: // hibernate-specific overrides to detect and warn about conflicting
035: // declarations
036: private final static String C3P0_STYLE_MIN_POOL_SIZE = "c3p0.minPoolSize";
037: private final static String C3P0_STYLE_MAX_POOL_SIZE = "c3p0.maxPoolSize";
038: private final static String C3P0_STYLE_MAX_IDLE_TIME = "c3p0.maxIdleTime";
039: private final static String C3P0_STYLE_MAX_STATEMENTS = "c3p0.maxStatements";
040: private final static String C3P0_STYLE_ACQUIRE_INCREMENT = "c3p0.acquireIncrement";
041: private final static String C3P0_STYLE_IDLE_CONNECTION_TEST_PERIOD = "c3p0.idleConnectionTestPeriod";
042: private final static String C3P0_STYLE_TEST_CONNECTION_ON_CHECKOUT = "c3p0.testConnectionOnCheckout";
043:
044: //swaldman 2006-08-28: define c3p0-style configuration parameters for initialPoolSize, which
045: // hibernate sensibly lets default to minPoolSize, but we'll let users
046: // override it with the c3p0-style property if they want.
047: private final static String C3P0_STYLE_INITIAL_POOL_SIZE = "c3p0.initialPoolSize";
048:
049: private DataSource ds;
050: private Integer isolation;
051: private boolean autocommit;
052:
053: /**
054: * {@inheritDoc}
055: */
056: public Connection getConnection() throws SQLException {
057: final Connection c = ds.getConnection();
058: if (isolation != null) {
059: c.setTransactionIsolation(isolation.intValue());
060: }
061: if (c.getAutoCommit() != autocommit) {
062: c.setAutoCommit(autocommit);
063: }
064: return c;
065: }
066:
067: /**
068: * {@inheritDoc}
069: */
070: public void closeConnection(Connection conn) throws SQLException {
071: conn.close();
072: }
073:
074: /**
075: * {@inheritDoc}
076: */
077: public void configure(Properties props) throws HibernateException {
078: String jdbcDriverClass = props.getProperty(Environment.DRIVER);
079: String jdbcUrl = props.getProperty(Environment.URL);
080: Properties connectionProps = ConnectionProviderFactory
081: .getConnectionProperties(props);
082:
083: log.info("C3P0 using driver: " + jdbcDriverClass + " at URL: "
084: + jdbcUrl);
085: log
086: .info("Connection properties: "
087: + PropertiesHelper.maskOut(connectionProps,
088: "password"));
089:
090: autocommit = PropertiesHelper.getBoolean(
091: Environment.AUTOCOMMIT, props);
092: log.info("autocommit mode: " + autocommit);
093:
094: if (jdbcDriverClass == null) {
095: log.warn("No JDBC Driver class was specified by property "
096: + Environment.DRIVER);
097: } else {
098: try {
099: Class.forName(jdbcDriverClass);
100: } catch (ClassNotFoundException cnfe) {
101: try {
102: ReflectHelper.classForName(jdbcDriverClass);
103: } catch (ClassNotFoundException e) {
104: String msg = "JDBC Driver class not found: "
105: + jdbcDriverClass;
106: log.fatal(msg, e);
107: throw new HibernateException(msg, e);
108: }
109: }
110: }
111:
112: try {
113:
114: //swaldman 2004-02-07: modify to allow null values to signify fall through to c3p0 PoolConfig defaults
115: Integer minPoolSize = PropertiesHelper.getInteger(
116: Environment.C3P0_MIN_SIZE, props);
117: Integer maxPoolSize = PropertiesHelper.getInteger(
118: Environment.C3P0_MAX_SIZE, props);
119: Integer maxIdleTime = PropertiesHelper.getInteger(
120: Environment.C3P0_TIMEOUT, props);
121: Integer maxStatements = PropertiesHelper.getInteger(
122: Environment.C3P0_MAX_STATEMENTS, props);
123: Integer acquireIncrement = PropertiesHelper.getInteger(
124: Environment.C3P0_ACQUIRE_INCREMENT, props);
125: Integer idleTestPeriod = PropertiesHelper.getInteger(
126: Environment.C3P0_IDLE_TEST_PERIOD, props);
127:
128: Properties c3props = new Properties();
129:
130: // turn hibernate.c3p0.* into c3p0.*, so c3p0
131: // gets a chance to see all hibernate.c3p0.*
132: for (Iterator ii = props.keySet().iterator(); ii.hasNext();) {
133: String key = (String) ii.next();
134: if (key.startsWith("hibernate.c3p0.")) {
135: String newKey = key.substring(10);
136: if (props.containsKey(newKey)) {
137: warnPropertyConflict(key, newKey);
138: }
139: c3props.put(newKey, props.get(key));
140: }
141: }
142:
143: setOverwriteProperty(Environment.C3P0_MIN_SIZE,
144: C3P0_STYLE_MIN_POOL_SIZE, props, c3props,
145: minPoolSize);
146: setOverwriteProperty(Environment.C3P0_MAX_SIZE,
147: C3P0_STYLE_MAX_POOL_SIZE, props, c3props,
148: maxPoolSize);
149: setOverwriteProperty(Environment.C3P0_TIMEOUT,
150: C3P0_STYLE_MAX_IDLE_TIME, props, c3props,
151: maxIdleTime);
152: setOverwriteProperty(Environment.C3P0_MAX_STATEMENTS,
153: C3P0_STYLE_MAX_STATEMENTS, props, c3props,
154: maxStatements);
155: setOverwriteProperty(Environment.C3P0_ACQUIRE_INCREMENT,
156: C3P0_STYLE_ACQUIRE_INCREMENT, props, c3props,
157: acquireIncrement);
158: setOverwriteProperty(Environment.C3P0_IDLE_TEST_PERIOD,
159: C3P0_STYLE_IDLE_CONNECTION_TEST_PERIOD, props,
160: c3props, idleTestPeriod);
161:
162: // revert to traditional hibernate behavior of setting initialPoolSize to minPoolSize
163: // unless otherwise specified with a c3p0.*-style parameter.
164: Integer initialPoolSize = PropertiesHelper.getInteger(
165: C3P0_STYLE_INITIAL_POOL_SIZE, props);
166: if (initialPoolSize == null && minPoolSize != null) {
167: c3props.put(C3P0_STYLE_INITIAL_POOL_SIZE, String
168: .valueOf(minPoolSize).trim());
169: }
170:
171: /*DataSource unpooled = DataSources.unpooledDataSource(
172: jdbcUrl, props.getProperty(Environment.USER), props.getProperty(Environment.PASS)
173: );*/
174: DataSource unpooled = DataSources.unpooledDataSource(
175: jdbcUrl, connectionProps);
176:
177: Properties allProps = (Properties) props.clone();
178: allProps.putAll(c3props);
179:
180: ds = DataSources.pooledDataSource(unpooled, allProps);
181: } catch (Exception e) {
182: log.fatal("could not instantiate C3P0 connection pool", e);
183: throw new HibernateException(
184: "Could not instantiate C3P0 connection pool", e);
185: }
186:
187: String i = props.getProperty(Environment.ISOLATION);
188: if (i == null) {
189: isolation = null;
190: } else {
191: isolation = new Integer(i);
192: log.info("JDBC isolation level: "
193: + Environment.isolationLevelToString(isolation
194: .intValue()));
195: }
196:
197: }
198:
199: /**
200: * {@inheritDoc}
201: */
202: public void close() {
203: try {
204: DataSources.destroy(ds);
205: } catch (SQLException sqle) {
206: log.warn("could not destroy C3P0 connection pool", sqle);
207: }
208: }
209:
210: /**
211: * {@inheritDoc}
212: */
213: public boolean supportsAggressiveRelease() {
214: return false;
215: }
216:
217: private void setOverwriteProperty(String hibernateStyleKey,
218: String c3p0StyleKey, Properties hibp, Properties c3p,
219: Integer value) {
220: if (value != null) {
221: c3p.put(c3p0StyleKey, String.valueOf(value).trim());
222: if (hibp.getProperty(c3p0StyleKey) != null) {
223: warnPropertyConflict(hibernateStyleKey, c3p0StyleKey);
224: }
225: String longC3p0StyleKey = "hibernate." + c3p0StyleKey;
226: if (hibp.getProperty(longC3p0StyleKey) != null) {
227: warnPropertyConflict(hibernateStyleKey,
228: longC3p0StyleKey);
229: }
230: }
231: }
232:
233: private void warnPropertyConflict(String hibernateStyle,
234: String c3p0Style) {
235: log.warn("Both hibernate-style property '" + hibernateStyle
236: + "' and c3p0-style property '" + c3p0Style
237: + "' have been set in hibernate.properties. "
238: + "Hibernate-style property '" + hibernateStyle
239: + "' will be used " + "and c3p0-style property '"
240: + c3p0Style + "' will be ignored!");
241: }
242: }
|